动态规划 ——正则表达式匹配,C++, 暴力动态规划解法+加备忘录解法

思路

不加备忘录的暴力思路

主要是* 星号, 据题意 星号 肯定是在某个字符的后面,时刻记住动态规划的主旨就是划分成子问题,那我们就一个一个去比较,当发现有*号时,就将 星号 与其前一个字母看作一个子问题, (并铭记关注当下),当下对于 星号 的处理就是两种情况,要么作用0次,那就将这个size为2的子串直接跳过去p = p.substr(2), 要么当下作用1次,与当下的s作比较s[0] == p[0],并s往后移, p是不动的,还要靠 星号 前面的正主来比较的
那么公式就是isMatch(s, p.substr(2)) || (当前是否相等 && isMatch(s.substr(1), p))
关于当前是否相等,就用到了’.’,点号,点号可以代替任意一个字符,所以first_place = (!s.empty() && (s[0] == p[0] ||p[0] == '.'))

综上isMatch(s, p.substr(2)) || (first_place && isMatch(s.substr(1), p))
小细节上的考量:在测试案例上有一个是aa和a*, 最后s走完了,p还有两个,所以我们在长度判断上要始终以p去判断s

加备忘录

加备忘录就是为了避免重复计算,这道题的重复计算会出现在什么情况呢,,,没想出来
那,可以看看是否会有子问题重叠的情况呢,从状态入手,假设i, j分别是当前s, p作用点的位置,那么根据上述思路,有下面几种状态,初始dp[i][j], 星号作用0次直接匹配串跳过两个dp[i][j+2], 星号作用1次s串往前走1个dp[i+1][j], 都往前走的dp[i+1][j+1]
那么判断是否有子问题重叠的关键就是看dp[i][j]到dp[i+2][j+2]是否超过一种路径可达,很明显在本题中有超过两种路径,所以有子问题

那,就用i、j存入备忘录避免重复计算吧(觉得画个图可能就立马能知道重复的情况,でも ま——)

题目

在这里插入图片描述

代码(不加备忘录

class Solution {
public:
    bool isMatch(string s, string p) {
        if(p.empty())
            return s.empty() ;
        bool first_place = (!s.empty() && (s[0] == p[0] ||p[0] == '.'));

        if(p.size() >1 && p[1] == '*')
        {//关注当下,作用0次直接跳过p的两个 || (先)作用1次,s往后走1,s还是要用那个*前面的元素的
            return (isMatch(s, p.substr(2)) || (first_place && isMatch(s.substr(1), p)));
        }
        else{
            return first_place && isMatch(s.substr(1), p.substr(1));
        }
    }
};
//aa a* 怎么判断呢 最后还有a 和a*的时候,正常走if,直到s空,p只有*,
//nonono p不是只有*了,作用1次,p是不往后走的,p还是a*, 所有还是走if上,此刻p也就空了,到第一个if

//不要以s去判断,以p的长度去判断,

加备忘录代码

class Solution {
public:
    bool dp(string &s, int i, string &p, int j, vector<vector<int>> &memo) {
        if (memo[i][j] != -1)
            return memo[i][j];
        
        if (j == p.length())
            memo[i][j] = (i == s.length());
        else if (j + 1 < p.length() && p[j + 1] == '*')
            memo[i][j] = dp(s, i, p, j + 2, memo) || i < s.length() && (s[i] == p[j] || p[j] == '.') && dp(s, i + 1, p, j, memo);
        else
            memo[i][j] = i < s.length() && (s[i] == p[j] || p[j] == '.') && dp(s, i + 1, p, j + 1, memo);
        
        return memo[i][j];
    }
    
    bool isMatch(string s, string p) {
        vector<vector<int>> memo(s.length() + 1, vector<int>(p.length() + 1, -1));
        return dp(s, 0, p, 0, memo);
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值