Given an input string (s
) and a pattern (p
), implement regular expression matching with support for '.'
and '*'
.
'.' Matches any single character. '*' Matches zero or more of the preceding element.
The matching should cover the entire input string (not partial).
Note:
s
could be empty and contains only lowercase lettersa-z
.p
could be empty and contains only lowercase lettersa-z
, and characters like.
or*
.
總結下問題:簡易的正則表達式匹配,如果s爲空,p也爲空,那麼匹配結果爲true;如果s爲"a",p爲"*",那麼匹配結果爲false;s只能是[a-z]的元素組成;p只能是[a-z.*]的元素組成.
思路:有兩種思路,遞歸和動態規劃。遞歸很好理解,網上的答案也是正確的。但是動態規劃的求解代碼,網上卻有很多的錯誤答案(官方還能運行通過!),這個會在後面驗證說明。
一,遞歸:考察p模式,@1 如果p爲空,那麼結果取決於s是否爲空,s爲空返回true,不爲空返回false. @2 如果p只有一個字符,那麼匹配結果取決於(s.size() ==1) && (s[0] == p[0] || p[0] == '.' ) @3 除了上述情況,那麼p至少有2個字符;對p的p[1]判斷,如果p[1]是非'*'字符,那麼結果取決於 s.empty() || (s[0] == p[0] || p[0] == '.' ) && isMatch(s.substr(1),p.substr(1))。 如果p[1]是'*'號,那麼判斷*號重複前面字符0次,1次,2次...是否匹配,一旦匹配返回true,否則每次判斷都縮小s的範圍,確保能循環終止。
二,動態規劃:參考官網上solution的jianchao-li的帖子,
P[i][j] = P[i - 1][j - 1]
, ifp[j - 1] != '*' && (s[i - 1] == p[j - 1] || p[j - 1] == '.')
;P[i][j] = P[i][j - 2]
, ifp[j - 1] == '*'
and the pattern repeats for0
times;P[i][j] = P[i - 1][j] && (s[i - 1] == p[j - 2] || p[j - 2] == '.')
, ifp[j - 1] == '*'
and the pattern repeats for at least1
times.
這個思路夠清晰了,但是貼出來的代碼卻是錯誤的,如果s="",p="*",程序立馬崩潰!但官網上還是能運行通過。
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.length(), n = p.length();
vector<vector<bool> > dp(m + 1, vector<bool> (n + 1, false));
dp[0][0] = true;
for (int i = 0; i <= m; i++)
for (int j = 1; j <= n; j++)
if (p[j - 1] == '*')
dp[i][j] = dp[i][j - 2] || (i > 0 && (s[i - 1] == p[j - 2] || p[j - 2] == '.') && dp[i - 1][j]);
else dp[i][j] = i > 0 && dp[i - 1][j - 1] && (s[i - 1] == p[j - 1] || p[j - 1] == '.');
return dp[m][n];
}
};
附加遞歸代碼:
附加動態規劃代碼:
附加測試用例: