//此为博客讲解
//p串中星号的位置很重要,用jStar来表示,还有星号匹配到s串中的位置,
//使用iStart来表示,这里 iStar 和 jStar 均初始化为 - 1,表示默认情况下是没有星号的。
//然后再用两个变量i和j分别指向当前s串和p串中遍历到的位置。
//
//开始进行匹配,若i小于s串的长度,进行while循环。若当前两个字符相等,
//或着p中的字符是问号,则i和j分别加1。若p[j] 是星号,那么我们要记录星号的位置,
//pStar赋为j,此时j再自增1,iStar赋为i。若当前p[j] 不是星号,并且不能跟p[i] 匹配上,
//那么此时就要靠星号了,若之前星号没出现过,那么就直接跪,比如 s = "aa" 和 p = "c*",
//此时 s[0] 和 p[0] 无法匹配,虽然p[1] 是星号,但还是跪。如果星号之前出现过,可以强行续一波命,
//比如 s = "aa" 和 p = "*c",当发现 s[1] 和 p[1] 无法匹配时,但是好在之前 p[0] 出现了星号,
//我们把 s[1] 交给 p[0] 的星号去匹配。至于如何知道之前有没有星号,这时就能看出 iStar 的作用了,
//因为其初始化为 - 1,而遇到星号时,其就会被更新为i,那么我们只要检测 iStar 的值,
//就能知道是否可以使用星号续命。虽然成功续了命,匹配完了s中的所有字符,但是之后我们还要检查p串,
//此时没匹配完的p串里只能剩星号,不能有其他的字符,将连续的星号过滤掉,如果j不等于p的长度,
//则返回false,参见代码如下:
1 class Solution { 2 public: 3 bool isMatch(string s, string p) { 4 int i = 0, j = 0, iStar = -1, jStar = -1; 5 while (i < s.size()) { 6 if (s[i] == p[j] || p[j] == '?') { 7 ++i; ++j; 8 } 9 else if (p[j] == '*') { 10 iStar = i; 11 jStar = j++; 12 } 13 else if (iStar >= 0) { 14 i = ++iStar; 15 j = jStar + 1; 16 } 17 else return false; 18 } 19 while (p[j] == '*') ++j; 20 return j == p.size(); 21 } 22 };
//使用动态规划
1 class Solution { 2 public: 3 bool isMatch(string s, string p) { 4 int m = s.size(), n = p.size(); 5 vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false)); 6 dp[0][0] = true; 7 for (int i = 1; i <= n; ++i) { 8 if (p[i - 1] == '*') dp[0][i] = dp[0][i - 1]; 9 } 10 for (int i = 1; i <= m; ++i) { 11 for (int j = 1; j <= n; ++j) { 12 if (p[j - 1] == '*') { 13 dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; 14 } 15 else { 16 dp[i][j] = (s[i - 1] == p[j - 1] || p[j - 1] == '?') && dp[i - 1][j - 1]; 17 } 18 } 19 } 20 return dp[m][n]; 21 } 22 };
//使用递归思想
//有三种不同的状态,返回0表示匹配到了s串的末尾,但是未匹配成功;
//返回1表示未匹配到s串的末尾就失败了;返回2表示成功匹配。
//那么只有返回值大于1,才表示成功匹配。至于为何失败的情况要分类,
//就是为了进行剪枝。在递归函数中,若s串和p串都匹配完成了,返回状态2。
//若s串匹配完成了,但p串但当前字符不是星号,返回状态0。若s串未匹配完,
//p串匹配完了,返回状态1。若s串和p串均为匹配完,且当前字符成功匹配的话,
//对下一个位置调用递归。否则若p串当前字符是星号,那么我们首先跳过连续的星号
//。然后我们分别让星号匹配空串,一个字符,两个字符,....,直到匹配完整个s串
//,对每种情况分别调用递归函数,接下来就是最大的亮点了,也是最有用的剪枝,
//当前返回值为状态0或者2的时候,返回,否则继续遍历。如果我们仅仅是状态2的时候才返回,
//因为当返回值为状态0的时候,已经没有继续循环下去的必要了,非常重要的一刀剪枝,参见代码如下:
1 class Solution { 2 public: 3 bool isMatch(string s, string p) { 4 return helper(s, p, 0, 0) > 1; 5 } 6 int helper(string& s, string& p, int i, int j) { 7 if (i == s.size() && j == p.size()) return 2; 8 if (i == s.size() && p[j] != '*') return 0; 9 if (j == p.size()) return 1; 10 if (s[i] == p[j] || p[j] == '?') { 11 return helper(s, p, i + 1, j + 1); 12 } 13 if (p[j] == '*') { 14 if (j + 1 < p.size() && p[j + 1] == '*') { 15 return helper(s, p, i, j + 1); 16 } 17 for (int k = 0; k <= (int)s.size() - i; ++k) { 18 int res = helper(s, p, i + k, j + 1); 19 if (res == 0 || res == 2) return res; 20 } 21 } 22 return 1; 23 } 24 };