10.正则表达式匹配
思路
动态规划
-
将
字符或'.' + '*'
当做一个整体进行处理,因此如果下一个位置是*
,那就跳过当前位置 -
当
p[j] != '*'
时,那就是字符匹配,此时i必须大于0,因为s[i]必须是一个字符才能进行匹配- 此时
dp[i][j] = dp[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
,即s[1~i]
和p[1~j]
匹配 等于s[1~i-1]
和p[1~j-1]
匹配以及s[i]
和p[j]
匹配
- 此时
-
当
p[j] == '*'
时,*可以表示任意个p[j - 1]
字符,*表示0个
p[j - 1]
,那就是F(i, j) = F(i, j - 2)
,即s[1~i]和p[1~j-2]
匹配*表示1个
p[j - 1]
,那就是F(i, j) = F(i - 1, j - 2) && s[i] == [j - 1]
即s[1~i - 1]
和p[1~j-2]
匹配,且s[i] == p[j - 1]
最后
dp[i][j] == 上述所有结果的或值
对p[j] == '*'
状态转移进行优化
dp[i - 1][j] = dp[i - 1][j - 2];
= dp[i - 2][j - 2] && s[i-1] == p[j-1]
= dp[i - 3][j - 2] && (s[i-1] == p[j-1] && s[i] == p[j-1])
显然dp[i - 1][j]
跟第二个转移方程的差别是dp[i][j - 2]
和s[i]==p[j-1]
,因此原方程可转换成
\(F(i, j) = f(i, j-2) || {f(i-1, j) \& s[i] == p[j - 1] }\)
代码
class Solution {
public:
bool isMatch(string s, string p) {
s = ' ' + s, p = ' ' + p;
int n = s.size(), m = p.size();
vector<vector<bool>> dp(n, vector<bool>(m));
dp[0][0] = true;
// i从0开始,因为空字符串和a*是匹配的
for(int i = 0; i < n; i++)
for(int j = 1; j < m; j++)
{
if(j + 1 < m && p[j + 1] == '*') continue;
if(i && p[j] != '*')
dp[i][j] = i && dp[i - 1][j - 1] && (s[i] == p[j] || p[j] == '.');
else if(p[j] == '*')
dp[i][j] = dp[i][j - 2] || i && dp[i - 1][j] && (s[i] == p[j - 1] || p[j - 1] == '.');
}
return dp[n - 1][m - 1];
}
};