题目描述特别简洁:
先贴代码:
class Solution { public : bool isMatch(string s ,string p){ int dp[100][100] = {0}; s.insert(0,1,'@');p.insert(0,1,'@'); //为了将空字符考虑在内,初始化插入@方便之后的操作 int ls = s.size(),lp = p.size(); dp[0][0] = 1; //初始化dp(p与s为空字符) for(int j = 1 ; j < lp; j++){ for(int i = 0; i < ls; i ++){ if(i != 0 && (s[i] == p[j] || p[j] == '.') && dp[i-1][j-1] == 1 ){ //直接匹配 dp[i][j] = 1; } else if(p[j] == '*') //当p[j]为*时情况较为复杂 { if(j - 2 >= 0 && dp[i][j - 2] == 1) //可以直接把零个随意字符通配Σ*忽略 { dp[i][j] = 1; } else if(i != 0 && (dp[i - 1][j] == 1 || dp[i - 1][j - 1] == 1) && (s[i] == p[j - 1] || p[j-1] == '.')) //将Σ*于n个Σ匹配 { dp[i][j] = 1; } } } } // for(int i = 0;i < lp; i++) //把dp打印出来用于debug // { // for(int j = 0;j < ls; j++) // { // cout << dp[j][i]; // } // cout<<endl; // } if(dp[ls - 1][lp - 1]) { cout << "ture"; return 1; } else{ cout << "false"; return 0; } } };
通过如下的样例说明状态转移的过程(本题难就难在状态转移的方式比较多样,这也导致用简单的递归方法解题非常困难):
Case #1:
aaa
a*a
(如果将三个a直接用a*通配掉了那就直接得到了一个false)
Solution #1:
ture
DP(dpij) #1:
(当s.substr(0,i)与p.substr(0,j)能够相互匹配时dpij = 1)
1 0 0 0 (空字符串)
0 1 0 0 (dpi-1 j-1 == 1 时 s[i] 与 p[j] 是等价的 就有 dpij = 1)
1 1 1 1 (p[j] == '*' 且 dpi j-2 == 1 这表明 考虑dpij的时候 ‘*’ 与它之前的 ‘Σ’ 可以视作 0 个Σ 于是 两个子字符串匹配 dpij = 1) (p[j] == '*' 且 dpi-1 j == 1 且 s[i] 与 p[j-1] (也就是Σ)能够匹配 则 dpij = 1)
0 1 1 1 (继续进行上面的状态转移,得到答案)
Case #2:
abp
.*t
Solution #2:
false
(虽然.*匹配任意字符串但是加上个t就不行了)
DP(dpij) #2:
1 0 0 0
0 1 0 0
1 1 1 1
0 0 0 0
Case #3:
bbbopctf
b*.*ctf
(若只想到用.*匹配后面所有的字符便无法匹配“ctf”)
Solution #3:
ture
DP(dpij) #3:
1 0 0 0 0 0 0 0 0
0 1 0 0 0 0 0 0 0
1 1 1 1 0 0 0 0 0
0 1 1 1 1 0 0 0 0
1 1 1 1 1 1 1 1 1
0 0 0 0 0 0 1 0 0
0 0 0 0 0 0 0 1 0
0 0 0 0 0 0 0 0 1
动态规划编写简单,优势明显。
来源:https://www.cnblogs.com/my-growth/p/12632703.html