一个hard的字符串dp问题
思路分析:
对于p中的一个小写字母或者'.'只能匹配到一个s中的一个字符,但是对于一个字符+'*'的组合,可以匹配到s中的多个字母,我们考虑采用动态规划对所有方案进行枚举.
而对于字符串dp问题,一个常见的二维模型是dp[len_s+1][len_p+1], dp[i][j]表示 使用s的前i个字母和p的前j个字母能否匹配上, 也就是s[0]...s[i-1] , p[0]...p[j-1], dp某一维是0,表示该维度对于的字符串为空
递推边界:
dp[0][0] = 1, dp[i][0] = 0 ,(i !=0) dp[0][i] (i !=0) 需要自己计算
状态转移方程:
对于dp[i][j], 我们其实只用考虑当前 p[j]是不是通配符* 这两种情况
1. p[j]=='*' 前面一定是字母(题目要求)
看p[j-1]==s[i] ? 如果相等,说明 当前匹配上了,那么可以是零次,一次,两次...
dp[i][j] = dp[i][j-2] or dp[i-1][j] (注意这里的dp[i][j-2]其实就是匹配成功零 次,dp[i-1][j]就是非零次,递归到前面的 i, j)
如果不相等,可以理解成匹配零次 dp[i][j] = dp[i][j-2]
2. p[j] !='*'
那就看当前的p[j]能不能匹配上s[i] 也就是 (s[i]==p[j] || p[j]=='.') ?
如果匹配不上,就是false
如果匹配上了, 就是 dp[i][j] = dp[i-1][j-1]
代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
int len_s=s.size(),len_p=p.size();
bool dp[len_s+1][len_p+1];
memset(dp,0,sizeof(dp));// dp[i][0] = 0 (i!=0) dp[0][i]需要初始化
dp[0][0]=1;
for(int j=1;j<=len_p;j++){
for(int i=0;i<=len_s;i++){
if(p[j-1]=='*'){
dp[i][j] = dp[i][j-2];
if(i && (s[i-1]==p[j-2] || p[j-2]=='.')) dp[i][j] |= dp[i-1][j];
//如果*前的字母匹配上了 那么给i撤一步 所以我们需要给dp[0][i]初始化
}else{
if(i && (s[i-1]==p[j-1] || p[j-1]=='.')){
dp[i][j] = dp[i-1][j-1];
}
}
}
}
return dp[len_s][len_p];
}
};