思路一:参考
主要思想如下:
由于*匹配多少个字符是不一定的,于是首先假设*不匹配任何字符。
当后续匹配过程中出错,采用回溯的方法,假设*匹配0个字符、1个字符、2个字符……i个字符,然后继续匹配。
因此s需要有一个spos指针,记录当p中的*匹配i个字符后,s的重新开始位置。
p也需要一个starpos指针指向*的位置,当回溯过后重新开始时,从starpos的下一位开始。
这边我参考了其他人的代码
class Solution { public: bool isMatch(string s, string p) { int ppos=0; int spos=0; int star=-1;//记录p字符串中当前的'*'的下标 int match;//记录p[ppos]=='*'时,spos的位置 while(spos<s.size()) { if(ppos<p.size()&&(s[spos]==p[ppos]||p[ppos]=='?'))//当前字符匹配 { spos++; ppos++; } else if(ppos<p.size()&&p[ppos]=='*')//当前字符不匹配 当前p[ppos]=‘×’ { match=spos; star=ppos++; } else if(star>=0)//当前字符不匹配 当前p[ppos]!=‘×’ 前一个模式串是'*' { ppos=star+1; spos=++match; } else return false; } while(ppos<p.size()&&p[ppos]=='*') ppos++; return ppos==p.size(); } };
方法二:递归
这需要说明一下如何理解“*可以匹配任意多字符”:其实这可以分为两种情况,我们用“aa”和“*a*”举例说明:
- aa 和 *a 已经匹配,由于最后一个字符是*,所以整个字符串是匹配的,换言之,如果遇到一个*,只要星号之前的串是匹配的,整体就是匹配的。
- a 和 *a 匹配,让剩下的一个 a 和最后的 * 匹配。
于是可以得出基本思路:扫描匹配串,遇到*就考虑上边的两种情况,也就是dp[i - 1][j] 和 dp[i][j - 1];如果遇到?,就让问号匹配当前字符,这就转换成了s[i - 1] 和 p[j - 1]是否匹配的问题。
class Solution { public: bool isMatch(string s, string p) { int m = s.size(), n = p.size(); vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false)); //dp[0][0]可以理解为空串和空串匹配 dp[0][0] = true; //dp[0][i]表示空串只能匹配到第一个* for (int i = 1; i <= n; ++i) { if (p[i - 1] == '*') { dp[0][i] = dp[0][i - 1]; } } for (int i = 1; i <= m; ++i) { for (int j = 1; j <= n; ++j) { if (p[j - 1] == '*') { //dp[i - 1][j]就是我们讨论的第一种情况 //dp[i][j - 1]是第二种情况 dp[i][j] = dp[i - 1][j] || dp[i][j - 1]; } else { dp[i][j] = (s[i - 1] == p[j - 1] || p[j - 1] == '?') && dp[i - 1][j - 1]; } } } return dp[m][n]; } };