题目:
这题难是真的难,不好思考到动态规划上面。虽然字符串匹配问题,动态规划基本上是通解,但是这题是真的难想。
大体上来说,分为两种情况。
p的当前字符是否为“*”?
如果是的话,则有两种选择:
让前一个字符重复一次或者删除掉前一个字符。(为什么不重复多次呢?因为是遍历,每一次只会考虑动态增长1或减少1的情况,多次增长交给下一次遍历去处理。这里我也是后来才想通)
那么重复的情况下,如果前一个字符是".",则也是可以令当前字符为True的。
如果不是:
则去匹配当前字符,同时,匹配的时候也检查p的当前字符是否为"."。这样就很明了。
除此之外,首行的初始化也要注意,因为p是可以出现"*"的。
所以即使s是空字符串,也会被p例如“a** ”这样的字符串匹配掉。
具体细节看代码:
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.length() + 1;
int n = p.length() + 1;
vector<vector<bool>> dp(m,vector<bool>(n,false));
dp[0][0] = true;//空字符串可以匹配
for(int j = 2;j<n;j++){
dp[0][j] = dp[0][j - 2] && p[j - 1] == '*';
}
for(int i=1;i<m;i++){
for(int j=1;j<n;j++){
if(p[j - 1] == '*') {
if(dp[i][j - 2]) dp[i][j] = true; // 1.舍弃掉p的i-1个字符
else if(dp[i - 1][j] && s[i - 1] == p[j - 2]) dp[i][j] = true; // 2.令p的字符重复一次
else if(dp[i - 1][j] && p[j - 2] == '.') dp[i][j] = true; // 3.令p的字符重复一次(与上面的情况相同)
} else {
if(dp[i - 1][j - 1] && s[i - 1] == p[j - 1]) dp[i][j] = true; // 1.普通字符配对
else if(dp[i - 1][j - 1] && p[j - 1] == '.') dp[i][j] = true; // 2.普通字符配对,p可以变成s【i-1】,本质上与第一种是一样的
}
}
}
return dp[m-1][n-1];
}
};
int main(){
string s = "aaa";
string p = "ab*.*";
Solution solution;
cout<<solution.isMatch(s,p);
}