1. 程式人生 > >LeetCode刷題之路(第三天)

LeetCode刷題之路(第三天)

10. 正則表示式匹配

給定一個字串 (s) 和一個字元模式 §。實現支援 ‘.’ 和 ‘*’ 的正則表示式匹配。

‘.’ 匹配任意單個字元。 ‘*’ 匹配零個或多個前面的元素。 匹配應該覆蓋整個字串 (s) ,而不是部分字串。

說明: s 可能為空,且只包含從 a-z 的小寫字母。 p 可能為空,且只包含從 a-z 的小寫字母,以及字元 . 和 。 示例 4: 輸入: s = “aab” p = "ca*b" 輸出: true 解釋: ‘c’ 可以不被重複, 'a’可以被重複一次。因此可以匹配字串 “aab”。 示例 5:

輸入: s = “mississippi” p = “mis* is* p*.” 輸出: false

這個問題可能猛一下子看起來很費解,無從下手,但是如果使用動態規劃的方法來思考,這個複雜的問題就迎刃而解了。我們首先建立動態規劃二維矩陣DP,其中DP[i][j]表示s的0到i-1和p的0到j-1的字串是否匹配。

如果s為空,而p中的偶數位為號,那麼這樣兩者也可以匹配成功 如果 p[j] == str[i] || pattern[j] == ‘.’, 此時dp[i][j] = dp[i-1][j-1]; 如果 p[j] == '’: 分兩種情況: 1: 如果p[j-1] != str[i] && p[j-1] != ‘.’, 此時dp[i][j] = dp[i][j-2] //*前面字元匹配0次 2: 如果p[j-1] == str[i] || p[j-1] == ‘.’ 此時dp[i][j] = dp[i][j-2] // *前面字元匹配0次 或者 dp[i][j] = dp[i][j-1] // *前面字元匹配1次 或者 dp[i][j] = dp[i-1][j] // *前面字元匹配多次

C++程式碼為:

class Solution {
public:
    bool isMatch(const char *s, const char *p) {
        int slen = strlen(s), plen = strlen(p);
        vector< vector<bool> > dp( slen+1, vector<bool>(plen+1, false) ); //增加一行用於特例
        dp[0][0] = true;
        for(int i = 1;i < plen + 1; i++){  //s為空的情況
            if(p[i -1] == '*')
                dp[0][i] = dp[0][i-2];
        }
        for(int i = 1;i < slen + 1; i++){
            for(int j = 1;j < plen + 1; j++){
                if(s[i-1] == p[j-1] || p[j-1] == '.'){
                    dp[i][j] = dp[i-1][j-1];
                }
                else if(p[j-1] == '*'){
                    if(p[j-2] != s[i-1] && p[j-2] != '.'){  // *前字元匹配到0次
                        dp[i][j] = dp[i][j-2];
                    }else{
                        if(p[j-2] == s[i-1] || p[j-2] == '.'){
                            dp[i][j] = dp[i][j-1] || dp[i][j-2] || dp[i-1][j];
                            // *前匹配到0次、1次、多次
                        }
                    }
                }
            }
        }
        return dp[slen][plen];
    }
};

11. 盛最多水的容器

給定 n 個非負整數 a1,a2,…,an,每個數代表座標中的一個點 (i, ai) 。在座標內畫 n 條垂直線,垂直線 i 的兩個端點分別為 (i, ai) 和 (i, 0)。找出其中的兩條線,使得它們與 x 軸共同構成的容器可以容納最多的水。 說明:你不能傾斜容器,且 n 的值至少為 2。 在這裡插入圖片描述

圖中垂直線代表輸入陣列 [1,8,6,2,5,4,8,3,7]。在此情況下,容器能夠容納水(表示為藍色部分)的最大值為 49。

首先大家都會想到暴力求解的方法,但是會花費很多的時間。我們可以想到最大面積一般是寬度較大,高也較大,故我們可以從這個vector的兩邊開始,然後比較這兩個的height,捨棄最小的那個值,保留最大的,只需要把資料遍歷一遍,那麼就可以得到我們所期望的最大值,其時間複雜度為O(n),空間複雜度為O(1)。 C++程式碼如下:

class Solution {
public:
    int maxArea(vector<int>& height) {
        int len = height.size();
        int l = 0, r = len-1, maxarea = 0;
        while(r>l){
            maxarea = max(maxarea , min(height[l], height[r]) * (r-l));
            height[l] <= height[r] ? l++ : r--;
          
        }
        return maxarea;
    }
};

12. 整數轉羅馬數字

羅馬數字包含以下七種字元: I, V, X, L,C,D 和 M。

字元 數值 I 1 V 5 X 10 L 50 C 100 D 500 M 1000

例如, 羅馬數字 2 寫做 II ,即為兩個並列的 1。12 寫做 XII ,即為 X + II 。 27 寫做 XXVII, 即為 XX + V + II 。

通常情況下,羅馬數字中小的數字在大的數字的右邊。但也存在特例,例如 4 不寫做 IIII,而是 IV。數字 1 在數字 5的左邊,所表示的數等於大數 5 減小數 1 得到的數值 4 。同樣地,數字 9 表示為 IX。這個特殊的規則只適用於以下六種情況: I 可以放在 V (5) 和 X (10) 的左邊,來表示 4 和 9。 X 可以放在 L (50) 和 C (100) 的左邊,來表示40 和 90。 C 可以放在 D (500) 和 M (1000) 的左邊,來表示 400 和 900。 給定一個整數,將其轉為羅馬數字。輸入確保在 1 到 3999 的範圍內。

class Solution {
public:
    string intToRoman(int num) {
        string res = "";
        vector<int> key = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1};
        vector<string> value={"M","CM","D","CD","C","XC","L","XL","X","IX","V","IV","I"};
        for(int i = 0;i < key.size(); i++){
            int count = num / key[i];
            for(int j = 0;j < count; j++){
                res += value[i];
            }
            num %= key[i];
        }
        return res;
    }
};

13. 羅馬數字轉整數

羅馬數字包含以下七種字元:I, V, X, L,C,D 和 M。

字元          數值

    I             1
    V             5
    X             10
    L             50
    C             100
    D             500
    M             1000

例如, 羅馬數字 2 寫做 II ,即為兩個並列的 1。12 寫做 XII ,即為 X + II 。 27 寫做 XXVII, 即為 XX + V + II 。

通常情況下,羅馬數字中小的數字在大的數字的右邊。但也存在特例,例如 4 不寫做 IIII,而是 IV。數字 1 在數字 5 的左邊,所表示的數等於大數 5 減小數 1 得到的數值 4 。同樣地,數字 9 表示為 IX。這個特殊的規則只適用於以下六種情況: I 可以放在 V (5) 和 X (10) 的左邊,來表示 4 和 9。 X 可以放在 L (50) 和 C (100) 的左邊,來表示 40 和 90。 C 可以放在 D (500) 和 M (1000) 的左邊,來表示 400 和 900。 給定一個羅馬數字,將其轉換成整數。輸入確保在 1 到 3999 的範圍內。

輸入: “MCMXCIV” 輸出: 1994 解釋: M = 1000, CM = 900, XC = 90, IV = 4.

程式碼如下:

class Solution {
public:
    int romanToInt(string s) {
        map<char,int> book = {{'I', 1}, {'V', 5}, {'X', 10}, {'L', 50}, 
                              {'C', 100}, {'D', 500}, {'M', 1000}};
        int res=0;
        for(int i=0;i<s.length();i++)
            if(i > 0 && book[s[i]] > book[s[i-1]]) res+= book[s[i]] - 2 * book[s[i-1]];
            else res+= book[s[i]];
        return res;
    }
};

14. 最長公共字首

編寫一個函式來查詢字串陣列中的最長公共字首。 如果不存在公共字首,返回空字串 “”。

示例 1: 輸入: [“flower”,“flow”,“flight”] 輸出: “fl” 示例 2: 輸入: [“dog”,“racecar”,“car”] 輸出: “” 解釋: 輸入不存在公共字首。

說明: 所有輸入只包含小寫字母 a-z 。

class Solution {
public:
    string longestCommonPrefix(vector<string>& strs) {
        if(strs.empty())
            return "";
        sort(strs.begin(), strs.end());  //排序後,只需要比較第一個和最後一個
        int n = strs.size();
        int l = min(strs[0].size(), strs[n-1].size());
        for(int i = 0;i < l; i++){
            if(strs[0][i] != strs[n-1][i])
                return strs[0].substr(0, i);
        }
        return strs[0].substr(0, l);  //全都符合的話,最大字首就是本身了
    }
};

宣告

以上程式碼均參考於牛客網並在牛客網測試成功。參考了各位大佬的思路整理而成,希望大家一起學習~