思路:动态规划
dp[i][j]表示前i个字符串能否用前j个模式串进行匹配。
这里为了方便i,j的下标从1开始(字符串是从0开始的)
dp[0][0]=1 两个空串必然可以匹配。
难点1:dp[0][j] 的问题,这个问题其实很重要,因为当遇到a*这样的串时,a*可以等价于空串。当p[j-1]=='*'时,我们应该考察
dp[0][j-2] ;
难点2:上面的问题属于初始化问题,下面就是状态转移了。
如s[i-1]==p[j-1] 则必有 dp[i][j]=dp[i-1][j-1]
若 p[j-1] =='.' 同理也有dp[i][j]=dp[i-1][j-1]
当p[j-1]=='*‘ &&(p[j-2]==s[i-1]||p[j-2\=='.')此时需要考虑三种情况。
第一 *和它前面的字符变为空串,则dp[i][j]=dp[i][j-2]
第二 *和它前面的字符变成一个 dp[i][j] = dp[i][j-1]
第三 *和它前面的字符可以匹配的元素大于2,例如 s="aaaa" p="a*" ,此时可以匹配全部的s。
关键在于这个该如何表示?表面上看,需要回退一个个试,但其实dp[i][j]=dp[i-1][j] 即可。
当p[j-1]=='*‘&&(p[j-2]!=s[i-1]&&p[j-2\!='.') 时,只能是当成空串处理 dp[i][j]=dp[i][j-2]
总结:状态转移比较难写,情况较多。属于较难的dp了。最难想的就是,想要匹配多个时,让dp[i][j]=dp[i-1][j]
class Solution {
public:
bool isMatch(string s, string p) {
int n1=s.size();
int n2=p.size();
bool dp[n1+3][n2+3];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(int i=0;i<=n1;i++)
{
for(int j=1;j<=n2;j++)
{
if(i==0)
{
if(p[j-1]=='*')
{
dp[i][j]=dp[0][j-2];
}
}
else{
if(s[i-1]==p[j-1])
{
dp[i][j]=dp[i-1][j-1];
}
else if(p[j-1]=='.')
{
dp[i][j]=dp[i-1][j-1];
}
else if(p[j-1]=='*')
{
if(p[j-2]==s[i-1]||p[j-2]=='.')
{
dp[i][j]=(dp[i][j-1]||dp[i][j-2]||dp[i-1][j]);
}
else{
dp[i][j]=dp[i][j-2];
}
}
}
//cout<<i<<" "<<j<<" "<<dp[i][j]<<endl;
}
}
return dp[n1][n2];
}
};
来源:CSDN
作者:untilyouydc
链接:https://blog.csdn.net/qq_40774175/article/details/104064475