LeetCode - 解題筆記 - 10- Regular Expression Matching
阿新 • • 發佈:2020-12-20
技術標籤:LeetCode解題筆記演算法字串
預覽
Regular Expression Matching
Solution 1
【官方題解】看到體面想到了非常複雜的星號匹配規則直接懵逼了……以為是狀態機,所以想到了DP,但是沒有對問題建模清楚。官方的題解很有分析意義,因此這裡直接使用這個題解。定義最優子結構ans[i][j]
表示輸入的第i+1
個字元及以後與正則的第j+1
個字元及以後的匹配結果。更新狀態按照正則匹配規則更新即可。邊界條件上有三個地方:如果正則為空,輸入只有為空時才匹配正確;二者的末尾空值匹配結果為dp[S][P] = true
dp[S][P-1]
不能直接置true
,因為如果正則末尾恰為星號需要額外進行判斷,需要在迭代時考慮正則與輸入末尾空值的比較。
這麼一看這個並不是很複雜,aaaa
和a*a*
的匹配我想複雜了,動態規劃可以將5種匹配方案都涵蓋進去。
- 時間複雜度: O ( S P ) O(SP) O(SP), S S S和 P P P分別是輸入和正則的長度
- 空間複雜度: O ( S P ) O(SP) O(SP), S S S和 P P P分別是輸入和正則的長度
class Solution {
public:
bool isMatch(string s, string p) {
// 邊界判定:空空為true
if (p.size() == 0) {
return s.size() == 0;
}
vector<vector<bool>> ans(s.size() + 1, vector<bool>(p.size() + 1, false));
ans[s.size()][p.size()] = true;
for (int i = s.size(); i >= 0; i--) {
// 這裡考察末尾空的情況主要是應對正則最後一個是*的情形
for (int j = p.size() - 1; j >= 0; j--) {
// 當前位置匹配:字母相同或者字母萬用字元
// 如果正則末尾是*,直接和輸入末尾空比較為負,否則會進入二者的末尾空比較,true
bool current = (i < s.size()) && (s.at(i) == p.at(j) || p.at(j) == '.');
// 星號判斷
if (j + 1 < p.size() && p.at(j + 1) == '*') {
// 0次,直接跳過p中的這兩個字元;任意多次,當前匹配正確並向後檢視s
ans[i][j] = (ans[i][j + 2] || current && ans[i + 1][j]);
} else {
ans[i][j] = current && ans[i + 1][j + 1];
}
// cout << i << j << ans[i][j] << endl;
}
}
return ans[0][0];
}
};
Solution 2
Solution 1的Python實現
class Solution:
def isMatch(self, s: str, p: str) -> bool:
if len(p) == 0:
return (len(s) == 0)
ans = [[False] * (len(p) + 1) for _ in range(len(s) + 1)]
# print(ans)
ans[len(s)][len(p)] = True
# print(len(s), len(p), ans)
for i in range(len(s), -1, -1):
for j in range(len(p) - 1, -1, -1):
current = (i < len(s)) and ((s[i] == p[j]) or (p[j] == '.'))
if j + 1 < len(p) and p[j + 1] == '*':
ans[i][j] = (ans[i][j + 2]) or (current and ans[i + 1][j])
else:
ans[i][j] = current and ans[i + 1][j + 1]
# print(i, j, ans[i][j], ans)
return ans[0][0]