Regular Expression Matching
Leetcode真的是一个不错的网站,全世界的人都在上面刷题,上面的题还是挺好的。现将我在上面做过的题写成解题报告,既是一种分享也是一个记录防止日后自己在转过头来看自己的解法又看不懂了。好了废话不多说
Regular Expression Matching题目大致意思是实现一个正则表达式支持’.’和’*’两种特殊符号,其匹配规则如下:
(1)’.’可以匹配任意单个字符
(2)‘*’可以匹配0个或多个前导符号,即该符号之前的一个字符
需要注意的是匹配过程需要完全匹配,而不是部分也就是说s,p两个字符串,匹配完之后s,p不能有再多余的字符
难度:难
例子:
isMatch("aa","a") → false
isMatch("aa","aa") → true
isMatch("aaa","aa") → false
isMatch("aa", "a*") → true
isMatch("aa", ".*") → true
isMatch("ab", ".*") → true
isMatch("aab", "c*a*b") → true
isMathc(“abc”, “a*b*c*) → true
倒数第二个例子可以理解为*可以消除前导符号,最后一个例子则说明*可以匹配0个字符
思路:
刚开始做的时候认为这道题没有甚麽特殊的,直接一个一个字符进行匹配。当WA了几次之后仔细思考才发现到了匹配过程中达到某一个状态可能有多种策略,这个时候立马想到可以通过回朔或者动态规划来解。于是当然选择了动态规划,因为可以避免重复计算
对于任意一个状态m[i][j]表示用j个字符匹配待匹配串i个字符是否能够匹配成功;经分析可以有5种策略转移到该状态上:
(1)当p[j]=’*’时只要当j-1个字符能够成功匹配i个字符即可,此时p[j]匹配0个字符即m[i][j] = m[i][j-1] (j>=1)
(2)当p[j]=’*’时,可以j-2个字符能够成功匹配i个字符即可,此时消除p[j]可以消除p[j-1]即m[i][j] = m[i][j-2] (j >= 2)
(3)当p[j]=’*’,此时p[j]可以向后扩展前导符号p[j-1]即可以在j个字符匹配好i-1个字符后通过扩展一个字符继续和第i个字符匹配则m[i][j] = m[i-1][j] && (p[j-1] == s[i] || p[j-1] == ‘.’) (i>= 1 && j >= 1)
(4)当p[j]=’*’,此时p[j]除了可以像第三种方式扩展之外还可以在第j-1个字符成功匹配第i-1个字符后再继续匹配第i个字符。则m[i][j] = m[i-1][j-1] && (p[j-1] == s[i] || p[j-1] == ‘.’) (i >= 1 && j >= 1)
(5)当p[j]为普通字符或者是’.’符号时,m[i][j] = m[i-1][j-1] && (p[j] == s[i] || p[j] == ‘.’) (i >= 1 && j >= 1)
边界情况讨论,从上述5中测录俄可以看出j或者i都必须大于等于1,而字符下标是从0开始的,为了能够匹配到所有的所有的字符这里m[1][1]表示第0个字符匹配第0个字符,而且没有状态能够转移到m[0][0]状态,所以需要手动赋值。m[0][0]需要赋成甚麽值需要具体讨论由这个状态转移到后续的某个状态的结果从而确定这个值是true还是false。代码如下:
class Solution {
public:
bool isMatch(string s, string p) {
int iLens = s.length();
int iLenp = p.length();
int i, j, k;
bool m[1000][1000] = {false};
m[0][0] = true;
bool bRet = false;
for(i = 0; i <= iLens; i ++)
{
for(j = 1; j <= iLenp; j ++)
{
if(j >= 1 && p[j - 1] == '*')
{
bRet = m[i][j - 1];
m[i][j] = m[i][j] > bRet ? m[i][j] : bRet;
}
if(j >= 2 && p[j - 1] == '*')
{
bRet = m[i][j - 2];
m[i][j] = m[i][j] > bRet ? m[i][j] : bRet;
}
if(i >= 1 && j >= 2 && p[j - 1] == '*')
{
bRet = m[i - 1][j - 1] && ( (s[i - 1] == p[j - 2]) || (p[j - 2] == '.') );
m[i][j] = m[i][j] > bRet ? m[i][j] : bRet;
}
if(i >= 2 && j >= 1 && p[j - 1] == '*')
{
bRet = m[i - 1][j] && ( (s[i - 1] == p[j - 2]) || (p[j - 2] == '.') );//p字符比s字符串短,*结尾
m[i][j] = m[i][j] > bRet ? m[i][j] : bRet;
}
if(i >= 1 && j >= 1)
{
bRet = m[i - 1][j - 1] && ( (s[i - 1] == p[j - 1]) || (p[j - 1] == '.') );
m[i][j] = m[i][j] > bRet ? m[i][j] : bRet;
}
}
}
//std::cout<<iLens<<" "<<iLenp<<std::endl;
//for(i = 0; i <= iLens; i ++)
//{
// for(j = 0; j <= iLenp; j ++)
// std::cout<<m[i][j]<<" ";
// std::cout<<std::endl;
// }
return m[iLens][iLenp];
}
};