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];
}
};
附加递归代码:
附加动态规划代码:
附加测试用例: