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); //全都符合的話,最大字首就是本身了
}
};
宣告
以上程式碼均參考於牛客網並在牛客網測試成功。參考了各位大佬的思路整理而成,希望大家一起學習~