这个题目对dp思想的理解和对dp问题边界问题的处理很有帮助。
题解:定义dp[i][j]表示s的前i个字符和p的前j个字符是否可以匹配。
假如说p的第j个字符和s的第i个字符一样,那么dp[i][j]=dp[i-1][j-1],不一样的话,直接就是false
如果p的第j个字符是?,那么一定可以匹配成功。dp[i][j]=dp[i-1][j-1]。
如果p的第j个字符是*,这里*可以用,也不使用,如果不适用*的话,dp[i][j]=dp[i][j-1],直接由j-1个转移过来,如果使用的话,因为我们会想到*可能跟i-k~i这个字符串进行匹配。那么转移方程就不好确定了,其实没必要这样。如果*和i之前的k个字符匹配,我们直接就把问题丢个i-1就好了,因为i-1一定在i-k~i之间。也就是说第j个和第i-1个匹配,所以转移方程为dp[i][j]=dp[i-1][j],*具体匹配多长的字符串,我们没必要知道,只需要把问题丢给i-1和j就好了,这也是dp问题的精要之处。
class Solution { public: bool isMatch(string s, string p) { int n=s.size(); int m=p.size(); vector<vector<int>> dp(n + 1, vector<int>(m + 1)); dp[0][0]=1; for(int i=0;i<p.size();i++){ if(p[i]=='*'){ dp[0][i+1]=1; } else break; } for(int j=0;j<p.size();j++){ for(int i=0;i<s.size();i++){ if(p[j]=='?'||p[j]==s[i]) dp[i+1][j+1]=dp[i][j]; else if(p[j]=='*') dp[i+1][j+1]=dp[i][j+1]|dp[i+1][j]; else if(p[j]>='a'&&p[j]<='z') dp[i+1][j+1]=false; } } return dp[s.size()][p.size()]; } };
另外vector开二维数组也挺好用的。vector<vector<int> > dp(n + 1, vector<int>(m + 1,x));这是一个(n+1)*(m+1)的初始值为x的二维数组。
还有关于边界处理,dp问题的边界值是后续的基础,一般都是dp[i][0]和dp[0][i]。这个问题的边界值dp[0][0]=1,dp[i][0]一定是false,dp[0][i],如果字符串p前i个是*,那么就是1,否则还是false.