- 题目地址及大意
- 回溯法
- 动态规划方法
题目地址及大意
题目leetcode 10 Regular Expression Matching大意如下:
给定两个字符串,s 与 p,其中 p 有可能包含 . 和 * 两种元素。其中, . 可以代表任何一个字符, * 代表它前面的字符重复 0 次或者更多次。 即 a* 可以代表 空字符, 只含有一个a,含有两个a……
题目刚开始看的时候我连题意都没有很理解,以为 a* 至少包含一个 a,所以题目就看了很久。解答时,看了很多题解,其中有两篇讲解的算是很清楚的,引用如下:
Voidsky博客
Pale Blue Dot博客
回溯法
在这种想法中,我们对 p 字符串从后往前读,如果 p[b]==‘*’,则判断 p[b-1]==s[a] || p[b-1]==’.’ 若以上两种情况中的一种满足,则我们可以认为 字符子串 p[b-1]p[b] 可以表示 s[a], 同时可以将 s 的下标向前移动一位,但即便上述这种情况成立,我们也无法判定 s[a] 确实由 p[b-1]p[b] 表示, 还要根据后续情况加以判断。具体代码如下:
if(p[b]=='*'){
if(a>=0 && (p[b-1] == '.' || p[b-1]==s[a])){
if(Match(s, a-1, p, b))
return true;
else
return Match(s, a, p, b-2);
}
else
return Match(s, a, p, b-2);
}
p[b] !=‘*’ 情况的判定则要简单许多,这里不再介绍,整体代码如下:
bool Match(string s, int a, string p, int b)
{
if(b<0){
if(a<0)
return true;
else
return false;
}
if(p[b]!='*'){
if(a>=0 && (p[b]=='.' || p[b]==s[a]))
return Match(s, a-1, p, b-1);
else
return false;
}
if(p[b]=='*'){
if(a>=0 && (p[b-1] == '.' || p[b-1]==s[a])){
if(Match(s, a-1, p, b))
return true;
else
return Match(s, a, p, b-2);
}
else
return Match(s, a, p, b-2);
}
}
class Solution {
public:
bool isMatch(string s, string p) {
return Match(s, s.size()-1, p, p.size()-1);
}
};
动态规划方法
在动态规划方法中,设立一个存储类型为 bool 型变量的二维数组, f[m+1][n+1], 其中, m=s.size(); n=p.size();
f[i][j] = true; 代表 s 的前 (i-1) 个字符的子串能够与 p 的前 (j-1) 个字符的子串相匹配。但要注意的是,此时情况可能会比较复杂。
f[0][0] = true; 表示 s 和 p 均为空字符串时,两者是匹配的。
f[i][0] = false; (i>0) 表示 p 为空字符串, s 却不为空的情况下, 两者不匹配。
对于 f[0][j] 的情况,有如下判断方式:
for(int j=1;j<=n;j++){
if(j>1)
f[0][j] = p[j-1]=='*' && f[0][j-2];
}
对于 f[i][j] (i>0, j>0) 而言,情况就更复杂一些:
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(p[j-1]=='*')
f[i][j] = f[i][j-2] || (f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1])); /*f[i][j-2]表示 p[j-2]p[j-1] 子串在当前 s 中不代表任何元素,(f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1])) 表示 p[j-2]p[j-1] 子串在当前 s 中已经代表 s[i-2],但仍可继续代表 s[i-1], 其中它仍可继续代表 s[i-1] 的条件即为 (p[j-2]=='.' || p[j-2]==s[i-1])*/
else
f[i][j] = f[i-1][j-1] && (s[i-1]==p[j-1] || p[j-1]=='.');
}
}
完整代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
int m = s.size();
int n = p.size();
vector<vector<bool>> f(m+1,vector<bool>(n+1, false));
f[0][0] = true;
for(int i=1;i<=m;i++){
f[i][0] = false;
}
for(int j=1;j<=n;j++){
if(j>1)
f[0][j] = p[j-1]=='*' && f[0][j-2];
}
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(p[j-1]=='*')
f[i][j] = f[i][j-2] || (f[i-1][j] && (p[j-2]=='.' || p[j-2]==s[i-1]));
else
f[i][j] = f[i-1][j-1] && (s[i-1]==p[j-1] || p[j-1]=='.');
}
}
return f[m][n];
}
};