LeetCode 10正则表达式匹配 (动态规划)

题目描述

在这里插入图片描述

回溯

老样子,写不出来动态规划先写暴力递归:
如果没有星号(正则表达式中的 * ),问题会很简单——我们只需要从左到右检查匹配串 s 是否能匹配模式串 p 的每一个字符。

当模式串中有星号时,我们需要检查匹配串 s 中的不同后缀,以判断它们是否能匹配模式串剩余的部分。一个直观的解法就是用回溯的方法来体现这种关系

如果模式串中有星号,它会出现在第二个位置,即 pattern[1]。这种情况下,我们可以直接忽略模式串中这一部分,或者删除匹配串的第一个字符,前提是它能够匹配模式串当前位置字符,即pattern[0] 。如果两种操作中有任何一种使得剩下的字符串能匹配,那么初始时,匹配串和模式串就可以被匹配。

    bool isMatch(string s, string p) {
        if(p.size() == 0) return !s.size();
        bool rs = (!s.empty() && (s[0] == p[0] || p[0] == '.'));
        if(p.size() >= 2 && p[1] == '*')
            return (rs && isMatch(s.substr(1,s.size()-1), p)) || isMatch(s, p.substr(2,p.size()-2));
        else
            return rs && isMatch(s.substr(1,s.size()-1), p.substr(1,p.size()-1));
    }
记忆化

直接在回溯的基础上增加记忆化,记录下已经算出结果的状态

    
    map<string,bool> mp;
    bool isMatch(string s, string p) {
        if(p.size() == 0) return !s.size();
        return dfs(s,p,0,0);
    }
    
    bool dfs(const string& s,const string& p, int i, int j)
    {
        string key = to_string(i) + "_" + to_string(j);
        if(mp.find(key) != mp.end()) return mp[key];
        bool ans;
        if( j == p.size())
            ans = i == s.size();
        else
        {
            bool rs = (i < s.size() && (s[i] == p[j] || p[j] == '.'));
        
            if(j + 1 < p.size() && p[j+1] == '*')
                ans =  (rs && dfs(s, p,i+1,j)) || dfs(s, p,i,j+2);
            else
                ans = rs && dfs(s, p,i+1,j+1);
        }
        mp.insert({key,ans});
        return ans;
    }    
动态规划

根据记忆化改迭代(记忆化为自顶向下方法,迭代为自底向上方法)

  bool isMatch(string s, string p) {
        vector<vector<bool>> dp(s.size()+1, vector<bool>(p.size() + 1, false));
        dp[s.size()][p.size()] = true;

        for (int i = s.size(); i >= 0; i--) {
            for (int j = p.size() - 1; j >= 0; j--) {
                bool first_match = (i < s.size() && (p.at(j) == s.at(i) || p.at(j) == '.'));
                if (j + 1 < p.size() && p.at(j + 1) == '*') {
                    dp[i][j] = dp[i][j + 2] || first_match && dp[i + 1][j];
                }
                else {
                    dp[i][j] = first_match && dp[i + 1][j + 1];
                }
            }
        }
        return dp[0][0];
    }

时间复杂度:用 TT 和 PP 分别表示匹配串和模式串的长度。对于i=0, … , Ti=0,…,T 和 j=0, … , Pj=0,…,P 每一个 dp(i, j)只会被计算一次,所以后面每次调用都是 O(1)O(1) 的时间。因此,总时间复杂度为 O(TP)O(TP) 。

空间复杂度:我们用到的空间仅有 O(TP)O(TP) 个 boolean 类型的缓存变量。所以,空间复杂度为 O(TP)O(TP) 。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值