动态规划合集(一)

LEECODE          No.10

先上题:

给你一个字符串 s 和一个字符规律 p,请你来实现一个支持 '.' 和 '*' 的正则表达式匹配。

'.' 匹配任意单个字符

'*' 匹配零个或多个前面的那一个元素

所谓匹配,是要涵盖 整个 字符串 s的,而不是部分字符串。

 

借鉴之前一个老哥的方法分三步:

  1. 定义dp数组的含义
  2. 找到dp数组的递推关系(最优子结构)
  3. 找dp数组初始值

 

1.首先定义dp[i][j]数组含义

             dp[i][j]表示 s 的前 i 个和 p 的前 j 个能匹配,为布尔值。

 

2.确定状态转移方程

            从dp[i-1][j-1]入手,首先分为两种情况:

 

  1. P[j]=s[i]:此时由dp[i-1][j-1] => dp[i][j]

 

  1. P[j]!=s[i]:此时分为两种情况

 

  • P[j]="." :此时可代表任意一个字符,可由dp[i-1][j-1] => dp[i][j]
  • P[j]="*" :此时是否匹配要看P[j-1],分两种情况如下

 

  • P[j-1]!=s[i] :由dp[i][j-2] => dp[i][j],例如 S  ____a
                                                                     P ____b*  即____a和____必须匹配,b*匹配成零个元素

 

  • P[j-1]=s[i] or P[j-1]="."      dp[i−1][j] => dp[i][j]dp[i][j-2] => dp[i][j]

 

3. 确定dp矩阵的初始值和边界 

                         需要注意dp矩阵需要大一圈来储存S或P为空的情况

                         i>=1, j>=1

                       初始值dp[0][0]=true, dp[i][0]=false,  dp[0][j]情况有两种  a. j=1 || p[j-1] !=" * "  =>  dp[0][j] = false

                                                                                                              b.反之 j != 1 &&  p[j-1] = " * "   =>   dp[0][j] = dp [0][j-2]

 

附代码如下:

/**
 * @param {string} s 
 * @param {string} p 
 * @returns {string} boolean
 * 
 */

let isMatch = (s, p) => {
    //初始化dp数组,须比s,p大一圈用来储存s或p为空的情况
    //dp[i][j]表示 s 的前 i 个和 p 的前 j 个能匹配
    let dp = Array(s.length+1);
    for (let i=0; i<dp.length; i++){
        //初始化包含dp[i][0]=false这种情况,后面无需再赋值
        dp[i] = Array(s.length+1).fill(false);
    }
    dp[0][0] = true;
    //考虑dp[0][j]有两种情况
    for (let j=1; j<p.length+1; j++){
        //j = 1 || p[j−1] != "∗"
        if(j == 1 || p.charAt(j-1)) dp[0][j] = false;
        //j != 1 && p[j−1] = "∗"
        else dp[0][j] = dp[0][j-2];
    }

    //分情况讨论
    for (let i=1; i<=s.length; i++){        //最外围不用
        for(let j=1; j<=p.length; j++){
            if(p.charAt(j) === '.' || p.charAt(j) === s.charAt(i)){
                dp[i][j] = dp[i-1][j-1];
            }
            if(p.charAt(j) == '*'){
                if(p.charAt(j-1) != s.charAt(i)){
                    //考虑边界防止数组溢出
                    if(j == 1) dp[i][j] = false;
                    else dp[i][j] = dp[i][j-2];
                }else if(p.charAt(j-1) == s.charAt(i) || p.charAt(j-1) == '.'){
                    dp[i][j] = dp[i-1][j] || dp[i][j-2];
                }
            }
        }
    }
    return dp[s.length][p.length];
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值