• 【动态规划】392. 判断子序列、115. 不同的子序列


    提示:努力生活,开心、快乐的一天


    392. 判断子序列

    题目链接:392. 判断子序列

    💡解题思路

    1. 该题与1143.最长公共子序列基本一致,不同点主要有2个
      • 本题如果删元素一定是字符串t,而 1143.最长公共子序列 是两个字符串都可以删元素。这就导致在确定递推公式的时候,针对(s[i - 1] != t[j - 1])情况,两道题的公式不一样
      • 最终返回结果,该题需要返回的是dp[s.length][t.length](最长公公子序列的长度)与s.length是否相等
    2. 动规五部曲
    • 确定dp数组以及下标的含义:dp[i][j] 表示以下标i-1为结尾的字符串s,和以下标j-1为结尾的字符串t,相同子序列的长度为dp[i][j]
    • 确定递推公式:主要就是两大情况: s[i - 1] 与 t[j - 1]相同,s[i - 1] 与 t[j - 1]不相同
      如果s[i - 1] == t[j - 1]相同,那么找到了一个公共元素,所以dp[i][j] = dp[i - 1][j - 1] + 1;
      如果s[i - 1] 与 t[j - 1]不相同,此时相当于t要删除元素,t如果把当前元素t[j - 1]删除,那么dp[i][j] 的数值就是 看s[i - 1]与 t[j - 2]的比较结果了,即:dp[i][j] = dp[i][j - 1];
      和 1143.最长公共子序列 (opens new window)的递推公式基本那就是一样的,区别就是 本题 如果删元素一定是字符串t,而 1143.最长公共子序列 是两个字符串都可以删元素
    • dp数组如何初始化:dp[i][0] = 0;dp[0][j] = 0
    • 确定遍历顺序:从递推公式,可以看出,有三个方向可以推出dp[i][j]在这里插入图片描述
    • 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来在这里插入图片描述

    🤔遇到的问题

    1. 最后的返回结果,是dp[s.length][t.length](最长公公子序列的长度)与s.length是否相等

    💻代码实现

    动态规划

    var isSubsequence = function (s, t) {
        let dp = new Array(s.length + 1).fill(0).map(x => new Array(t.length + 1).fill(0))
        for (let i = 1; i <= s.length; i++) {
            for (let j = 1; j <= t.length; j++) {
                if (s[i - 1] === t[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1
                } else {
                    dp[i][j] = dp[i][j - 1]
                }
            }
        }
        return dp[s.length][t.length] === s.length ? true : false
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    🎯题目总结

    dp[i][j]表示以下标i-1为结尾的字符串s和以下标j-1为结尾的字符串t 相同子序列的长度,所以如果dp[s.size()][t.size()] 与 字符串s的长度相同说明:s与t的最长相同子序列就是s,那么s 就是 t 的子序列。


    115. 不同的子序列

    题目链接:115. 不同的子序列

    💡解题思路

    1. 动规五部曲
    • 确定dp数组以及下标的含义:dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]
    • 确定递推公式:主要就是两大情况: s[i - 1] 与 [j - 1]相同,s[i - 1] 与 t[j - 1]不相同
      如果s[i - 1] 与 t[j - 1]相同,dp[i][j]可以有两部分组成:
      一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1];一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j]。dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];
      如果s[i - 1] 与 t[j - 1]不相同,dp[i][j]只有一部分组成,不用s[i - 1]来匹配(就是模拟在s中删除这个元素),即:dp[i - 1][j]
    • dp数组如何初始化:
      dp[i][0] = 1;dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数,以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1
      dp[0][j] = 0;dp[0][j]表示:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数,那么dp[0][j]一定都是0,s如论如何也变成不了t
      特殊位置:dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串t
    • 确定遍历顺序:从递推公式,可以看出,有三个方向可以推出dp[i][j]在这里插入图片描述
    • 举例推导dp数组:按照递推公式推导一下做推导,如果发现结果不对,就把dp数组打印出来在这里插入图片描述

    🤔遇到的问题

    1. 因为dp[i][j]的含义,所以在遍历s和t的时候,都可以等于s.length或者t.length

    💻代码实现

    动态规划

    var numDistinct = function (s, t) {
        //s:父
        //t:子
        let dp = new Array(s.length + 1).fill(0).map(x => new Array(t.length + 1).fill(0))
        //t为空字符串时
        for (let i = 0; i <= s.length; i++) {
            dp[i][0] = 1
        }
        for (let i = 1; i <= s.length; i++) {
            for (let j = 1; j <= t.length; j++) {
                if (s[i - 1] === t[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j]
                } else {
                    dp[i][j] = dp[i - 1][j]
                }
            }
        }
        console.log(dp)
        return dp[s.length][t.length]
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    🎯题目总结

    重点需要关注的是:当s[i - 1] 与 t[j - 1]相等时,dp[i][j]可以有两部分组成。
    一部分是用s[i - 1]来匹配,那么个数为dp[i - 1][j - 1]。即不需要考虑当前s子串和t子串的最后一位字母,所以只需要 dp[i-1][j-1]。
    一部分是不用s[i - 1]来匹配,个数为dp[i - 1][j]。

    🎈今日心得

    编辑距离的题目感觉代码很简单,但是思路确实比较难,也不容易想到

  • 相关阅读:
    用ARM进行汇编语言编程(5) 使用链接寄存器进行分支并返回和从堆栈内存中保存和检索数据
    buuctf----firmware
    使用Avalonia跨Linux平台
    谈谈ThreadLocal那些事
    跟我学Python图像处理丨基于灰度三维图的图像顶帽运算和黑帽运算
    电子器件系列52:达林顿晶体管阵列
    08.爱芳地产项目小程序全栈项目经验(已上线)
    基于WOA的VMD超参数优化
    Cmake qt ,vtkDataArray.cxx.obj: File too big
    面试官让你说说react状态管理?
  • 原文地址:https://blog.csdn.net/lx1234lj/article/details/133900855