题目
描述
实现支持 ‘.’ 和 ‘’ 的正则表达式匹配。’.’ 匹配任意一个字母。’’ 匹配零个或者多个前面的元素,’’ 前保证是一个非 '’ 元素。匹配应该覆盖整个输入字符串,而不仅仅是一部分。需要实现的函数是:
bool isMatch(string s, string p)
isMatch(“aa”,“a”) → false
isMatch(“aa”,“aa”) → true
isMatch(“aaa”,“aa”) → false
isMatch(“aa”, “a*”) → true
isMatch(“aa”, “.* ") → true
isMatch(“ab”, ". *”) → true
样例
样例 1:
输入:“aa”,“a”
输出:false
解释:
无法匹配
样例 2:
输入:“aa”,“a*”
输出:true
解释:
‘*’ 可以重复 a
样例 3:
输入:“aab”, “cab”
输出:true
解释:
“c*” 作为一个整体匹配 0 个 ‘c’ 也就是 “”
“a*” 作为一个整体匹配 2 个 ‘a’ 也就是 “aa”
“b” 匹配 “b”
所以 “cab” 可以匹配 “aab”
分析
解读题意,给定两个字符串,s和p,s是正常的字符串,p是带符号的字符串,‘.’可以匹配任意的一个字符,比如“a”和‘.’是匹配的,和前置的元素可以匹配0个或多个字符比如“aaaa”和“a ”是匹配的,“aaaa”和“. *”是匹配的。
这道给定了两个序列,所以依然是一道双序列的动态规划,被列为困难题,无非是多了很多匹配的条件,情况变得更多了,依然分析最后一步,然后分析转移方程
最后一步
情况一
A:abc…a
B:dads…a
先看最后一个字符不是*的情况,当两个序列最后一个字符匹配时,我们只需要比较他们前面的序列是否匹配,如果前面的匹配这两个序列就是匹配的f[i][j]=f[i][j]||f[i-1][j-1]
情况二
A:abc…a
B:abc…b
当最后的字符不相同时那一定是不匹配的,我们不需要任何操作,只需要初始化的时候将所有状态都设置成false即可
情况三
A:abc…a
B:abs…’.’
当最后一个字符为‘.’的时候也是跟情况一相同的,因为‘.’可以匹配任意一个字符
下面是最后一个字符为‘*’的时候的情况
情况一
A:asfad…a
B:sada…a*
这个时候最后一个字符是匹配的,但是的概念是可以当作0个或者多个,这个时候我们可以选择用这个a 匹配或者不用这个,f[i][j]=f[i][j] || f[i-1][j] (用a*) ||f[i][j-2] (不用a*)
情况二
A: sad…a
B: sad…’.’*
‘.’可以当作任意一个字符,所以这种情况等同于情况一,我们也可以用它,或者不用他
情况三
A:as…a
B: asd…b*
这个时候最后一个字符不匹配,但是整体不一定不匹配,因为也可以当作0个字符,这个时候不用b *前面的字符串如果匹配的话,这两个字符串也是匹配的,f[i][j]=f[i][j] || f[i][j-2]
转移方程
将最后一步的所有情况都总结起来转移方程就出来了
代码部分
初始化
我们要有空串的情况,所以状态的行和列都应该是字符串的长度加一
int slen=s.size();
int plen=p.size();
//f[i][j]:p的前j-1项是否跟s的前i-1项匹配
vector<vector<bool> > f(slen+1,vector<bool>(plen+1));
考虑p为空但是s不为空时,一定是无法匹配的的,所以值都设置为false,考虑都为空时一定匹配,所以0,0的值时true,考虑p不为空但是s为空时,有可能匹配“ ” “a*”因为*可以认为是0个当前元素,但是要是“ ” “a”就不匹配,所以我们将这种情况直接带入到转移方程中写
完整代码
class Solution {
public:
bool isMatch(string &s, string &p) {
int slen=s.size();
int plen=p.size();
//f[i][j]:p的前j-1项是否跟s的前i-1项匹配
vector<vector<bool> > f(slen+1,vector<bool>(plen+1));
for(int i=0;i<=slen;i++)
{
for(int j=0;j<=plen;j++)
{
if(i==0&&j==0) //空串匹配空串
{
f[i][j]=true;
continue;
}
if(j==0) //当p为空且s不为空一定不匹配
{
f[i][j]=false;
continue;
}
f[i][j]=false;
if(p[j-1]!='*')
{
if(i-1>=0&&(p[j-1]=='.'||p[j-1]==s[i-1]))
f[i][j]=f[i][j]||f[i-1][j-1];
}
else
{
if(i-1>=0&&j-2>=0&&(p[j-2]==s[i-1]||p[j-2]=='.'))
f[i][j]=(f[i][j]||f[i-1][j]||f[i][j-2]);
else if(j-2>=0)
f[i][j]=f[i][j]||f[i][j-2];
}
}
}
return f[slen][plen];
}
};
总结:
一道双序列型动态规划,之所以被列为困难题,难点在于情况要多一些,将每个情况都一 一分析出来,然后写出转移方程,在转换成代码,注意的点是要在条件中加上对数组下标的判断,不然会导致越界访问