给出两个字符串s、p,'.'可以匹配任意一个字符,'*'可以将其前一个的字符重复任意次数,也可以重复0次(ab*可以表示ab、abb,也可以表示a),问是否可以匹配成功。
应该算是比较明显的动态规划吧,一看就猜是动态规划,不过leetcode是没有数据范围的,不知道比较暴力的方法能不能过。虽然很快看出来了,但是太久没写过dp了,调了好久才好。
好,说重点,我用dp[i][j]表示s的前i个和p的前j个是否能成功匹配(其实*会打破这个定义,但是不会影响结果的正确性)。如果p[j]是'.'或者普通字符且与s[i]相等的话很简单 ,就是dp[i + 1][j + 1] |= dp[i][j],p[j]是*的话就会比较复杂,四种情况:
-
*和前一个字符不匹配,则i不变,j后移两个(从j-1到j+1,即放弃p[j-1])
-
跳过*,j后移一位,
-
*重复前一个字符串且仅重复这一次,i和j均后移一位,并且要判断p[j - 1]和s[i]是否匹配
-
*重复前一个字符并保留*继续向前匹配,即i后移一位j不懂,同样要判断p[j - 1]和s[i]是否匹配(这一种情况破坏了dp[i][j]的定义)。
代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
vector<vector<int> > dp(s.size() + 2, vector<int>(p.size() + 2, 0));
dp[0][0] = 1;
for(int j = 0; j <= p.size(); j++) {
for(int i = 0; i <= s.size(); i++) {
//if(dp[i][j] == 0) continue;
if(p[j] == '.' || p[j] == s[i]) dp[i + 1][j + 1] |= dp[i][j];
if(p[j] == '*' && j) {
dp[i][j + 1] |= dp[i][j];
dp[i][j + 1] |= dp[i][j - 1];
dp[i + 1][j + 1] |= dp[i][j] && (p[j - 1] == '.' || p[j - 1] == s[i]);
dp[i + 1][j] |= dp[i][j] && (p[j - 1] == '.' || p[j - 1] == s[i]);
}
}
}
return dp[s.size()][p.size()];
}
};