LeetCode OJ10 Regular Expression Matching

LeetCode OJ10 Regular Expression Matching

题目要求

Implement regular expression matching with support for ‘.’ and ‘*’.

‘.’ Matches any single character.
‘*’ Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be:
bool isMatch(const char *s, const char *p)

Some examples:
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

解题思路

基本思路, 就是动态规划

if(str1[0]==str2[0])str2[1]==if(str1[0]!=str2[0]str[2]==.,x

代码展示

mycode 1

这是我们早先写的代码, 用时32ms

class Solution {
public:
    bool isMatch_(char * ps, int m, char * pp, int n)
    {
        if (n == 0)
            return m == 0 ? true : false;

        if (n == 1)
        {
            if (m == 1 && (*ps == *pp || *pp == '.'))
                return true;

            return false;
        }

        if (m == 0)
        {
            if (pp[1] == '*')
                return isMatch_(ps, m, pp + 2, n - 2);

            return false;
        }

        // n > 1
        if (pp[1] != '*')
        {
            if (ps[0] == pp[0] || pp[0] == '.')
                return isMatch_(ps + 1, m - 1, pp + 1, n - 1);

            return false;
        }

        if (pp[1] == '*')
        {
            if (ps[0] == pp[0])
                return isMatch_(ps + 1, m - 1, pp, n) || isMatch_(ps, m, pp + 2, n - 2);

            if (ps[0] != pp[0] && pp[0] != '.')
                return isMatch_(ps, m, pp + 2, n - 2);

            // .*
            if (ps[0] != pp[0] && pp[0] == '.')
                return isMatch_(ps, m, pp + 2, n - 2) || isMatch_(ps + 1, m - 1, pp, n);
        }

    }

    bool isMatch(string s, string p) {
        return isMatch_(&s[0], s.size(), &p[0], p.size());
    }
};

mycode2

这段代码, 是今天 2015. 10. 12 写下的, 思路比较清晰, 但是运行下来时间用了 648 ms, 是之前的解法的20倍之多,效率太低, 主要原因是, 这里使用了各种string的拷贝构造, 带来很大的消耗

class Solution {
public:
    bool isMatch(string s, string p) {
        if (p.size() == 0)
            return s.size() == 0 ? true : false;
        else if (p.size() == 1){
            if (s.size() == 0)
                return false;
            else if (p[0] != s[0] && p[0] != '.')
                return false;
            /*
            else if (p[0] != s[0] && p[0] == '.')
                return isMatch(s.substr(1), p.substr(1));*/
            else /*if (p[0] == s[0])*/
                return isMatch(s.substr(1), p.substr(1));
        }else{
            if (s.size() == 0)
                return p[1] == '*' ? isMatch(s, p.substr(2)) : false;

            if (s[0] == p[0]){
                if (p[1] != '*'){
                    return isMatch(s.substr(1), p.substr(1));
                }else{
                    return isMatch(s.substr(1), p) || isMatch(s, p.substr(2));
                }
            }else{
                if (p[0] == '.' && p[1] == '*'){
                    return isMatch(s.substr(1), p) || isMatch(s, p.substr(2));
                }else if (p[0] == '.' && p[1] != '*'){
                    return isMatch(s.substr(1), p.substr(1));
                }else if (p[0] != '.' && p[1] == '*'){
                    return isMatch(s, p.substr(2));
                }else{
                    return false;
                }
            }
        }
    }
};

mycode3

在分析code2的基础上, 我们试图利用string的移动构造, 改进程序的效率, 运行时间为 396ms, 提升不是很大

class Solution {
public:
    bool _isMatch(string && s, string && p) {
        if (p.size() == 0)
            return s.size() == 0 ? true : false;
        else if (p.size() == 1){
            if (s.size() == 0)
                return false;
            else if (p[0] != s[0] && p[0] != '.')
                return false;
            /*
            else if (p[0] != s[0] && p[0] == '.')
                return _isMatch(s.substr(1), p.substr(1));*/
            else /*if (p[0] == s[0])*/
                return _isMatch(s.substr(1), p.substr(1));
        }else{
            if (s.size() == 0)
                return p[1] == '*' ? _isMatch(std::move(s), p.substr(2)) : false;

            if (s[0] == p[0]){
                if (p[1] != '*'){
                    return _isMatch(s.substr(1), p.substr(1));
                }else{
                    return _isMatch(s.substr(1), std::move(p)) || _isMatch(std::move(s), p.substr(2));
                }
            }else{
                if (p[0] == '.' && p[1] == '*'){
                    return _isMatch(s.substr(1), std::move(p)) || _isMatch(std::move(s), p.substr(2));
                }else if (p[0] == '.' && p[1] != '*'){
                    return _isMatch(s.substr(1), p.substr(1));
                }else if (p[0] != '.' && p[1] == '*'){
                    return _isMatch(std::move(s), p.substr(2));
                }else{
                    return false;
                }
            }
        }
    }

    bool isMatch(string s, string p){
        return _isMatch(std::move(s), std::move(p));
    }
};

大神们的代码

demo 1

大神考虑的方式和我么不太一样, 他主要使用 判断 ‘*’, 并使用了带记录的DP算法, 效率明显比我们的要高!!!

class Solution {
public:
    bool isMatch(string s, string p) {
        if (p.empty())    return s.empty();

        if ('*' == p[1])
            // x* matches empty string or at least one character: x* -> xx*
            // *s is to ensure s is non-empty
            return (isMatch(s, p.substr(2)) || !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p));
        else
            return !s.empty() && (s[0] == p[0] || '.' == p[0]) && isMatch(s.substr(1), p.substr(1));
    }
};

class Solution {
public:
    bool isMatch(string s, string p) {
        /**
         * f[i][j]: if s[0..i-1] matches p[0..j-1]
         * if p[j - 1] != '*'
         *      f[i][j] = f[i - 1][j - 1] && s[i - 1] == p[j - 1]
         * if p[j - 1] == '*', denote p[j - 2] with x
         *      f[i][j] is true iff any of the following is true
         *      1) "x*" repeats 0 time and matches empty: f[i][j - 2]
         *      2) "x*" repeats >= 1 times and matches "x*x": s[i - 1] == x && f[i - 1][j]
         * '.' matches any single character
         */
        int m = s.size(), 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;
        // p[0.., j - 3, j - 2, j - 1] matches empty iff p[j - 1] is '*' and p[0..j - 3] matches empty
        for (int j = 1; j <= n; j++)
            f[0][j] = j > 1 && '*' == 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 - 1][j - 1] && (s[i - 1] == p[j - 1] || '.' == p[j - 1]);
                else
                    // p[0] cannot be '*' so no need to check "j > 1" here
                    f[i][j] = f[i][j - 2] || (s[i - 1] == p[j - 2] || '.' == p[j - 2]) && f[i - 1][j];

        return f[m][n];
    }
};

demo 2

4ms 版本

Just to build a DP table checked, where checked[i][j] indicates whether s[0..i-1] matches with p[0..j-1]. The recursive relationship is as below: To match with the empty string s[0..0] (i.e. to make checked[0][j]), P[0..j-1] has to meet: p[j-1]==’*’ (to cancel p[j-2]) and checked[0][j-2] == true; To match with the string s[0..i-1] (i.e. to make checked[i][j]), P[0..j-1] has to meet:

if p[j-1] ==’*’, then j must be larger than 1 (j>1) and
checked[i][j-2] (i.e. p[j-2] cancelled by ‘*’)
checked[i-1][j] && (s[i-1] ==p[j-2] || p[j-2] ==’.’) (s[i-1] matches with p[j-2] or ‘.’, )
if p[j-1] !=’*’, checked[i-1][j-1] && (s[i-1] ==p[j-1] || p[j-1] ==’.’)(i.e. s[i-1] matches with p[j-1] or ‘.’)

class Solution {

public:
    bool isMatch(string s, string p) {
        int sSize = s.size(), pSize = p.size(), i, j;
        bool checked[sSize+1][pSize+1];
//        fill_n(&matched[0][0], (sSize+1)*(pSize+1), false);

        for(j=2, checked[0][0]=true, checked[0][1]= false; j<=pSize; ++j) // match s[0..0]
            checked[0][j] = p[j-1] == '*'? checked[0][j-2]  : false;
        for(i=1; i<=sSize; ++i)
        for(j=1, checked[i][0]=false; j<=pSize; ++j)
        {
            if(p[j-1]=='*') // case (1)
                checked[i][j] = (j>1) && ( checked[i][j-2]  || ( ( checked[i-1][j]) && (s[i-1]== p[j-2] || p[j-2] == '.')) );
            else // case (2)
                checked[i][j] = checked[i-1][j-1] && (s[i-1] == p[j-1] || p[j-1] == '.');        
        }
        return checked[sSize][pSize];
    }
};

demo 3

这个使用的方法, 和我们写的第一段代码十分类似

class Solution {
private:
    bool helper(const string &s, const string &p, int sS, int pS)
    {
        int sSize = s.size(), pSize = p.size(), i, j; 
        if(pS==pSize) return sS ==sSize; // if p goes to its end, then only if s also goes to its end to return true;

        if(p[pS+1]!='*')
        {
           if( sS<sSize && (p[pS]==s[sS] || p[pS] == '.')) return helper(s, p, sS+1, pS+1);
        }
        else
        {
            if(helper(s, p, sS,pS+2)) return true;
            while(sS<sSize && (p[pS]==s[sS] || p[pS] == '.')) if(helper(s,p, ++sS, pS+2)) return true;
        }
        return false;
    }

public:
    bool isMatch(string s, string p) {
       helper(s, p, 0, 0); 
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值