leetcode 10 Regular Expression Matching

  • 题目地址及大意
  • 回溯法
  • 动态规划方法

题目地址及大意

题目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];
    }
};

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值