代码随想录Day39动态规划:115不同的子序列_583两个字符串的删除操作_72编辑距离_编辑距离总结

代码随想录Day39动态规划:115不同的子序列_583两个字符串的删除操作_72编辑距离_编辑距离总结

115不同的子序列

题目:给你两个字符串s和t,统计并返回在s的子序列中t出现的个数。测试用例保证结果在 32 位有符号整数范围内。

示例 1:输入:s = "rabbbit", t = "rabbit",输出:3

解释:如下所示, 有 3 种可以从 s 中得到 "rabbit" 的方案。

链接:https://leetcode.cn/problems/distinct-subsequences/

动规五部曲:
1 确定dp数组及其含义

dp[i][j]:以i-1为结尾的s子序列中出现以j-1为结尾的t的个数为dp[i][j]。

以i-1为结尾的s子序列中出现dp[i][j]个以j-1为结尾的t。

2 确定递推公式

这一类问题,基本是要分析两种情况

s[i - 1] 与 t[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]。所以当s[i - 1] 与 t[j - 1]相等时,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[i][j] = dp[i - 1][j];

3 初始化dp数组

每次当初始化的时候,都要回顾一下dp[i][j]的定义,不要凭感觉初始化。

dp[i][0] 表示:以i-1为结尾的s可以随便删除元素,出现空字符串的个数。

那么dp[i][0]一定都是1,因为也就是把以i-1为结尾的s,删除所有元素,出现空字符串的个数就是1。

dp[0][j]:空字符串s可以随便删除元素,出现以j-1为结尾的字符串t的个数。

那么dp[0][j]一定都是0,s如论如何也变成不了t。

dp[0][0]应该是1,空字符串s,可以删除0个元素,变成空字符串t。

4 确定遍历顺序

从上到下,从左到右
5 举例推导dp数组

java 复制代码
class Solution {
    public int numDistinct(String s, String t) {
        int[][] dp=new int[s.length()+1][t.length()+1];
        for(int i=0;i<=s.length();i++){
            dp[i][0]=1;
        }

        for(int i=1;i<=s.length();i++){
            for(int j=1;j<=t.length();j++){
                if(s.charAt(i-1)==t.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1]+dp[i-1][j];
                }else{
                    dp[i][j]=dp[i-1][j];
                }
            }
        }
        return dp[s.length()][t.length()];
    }
}

583两个字符串的删除操作

题目:给定两个单词word1和word2,返回使得word1和word2相同所需的最小步数。每步可以删除任意一个字符串中的一个字符。

示例1:输入: word1 = "sea", word2 = "eat",输出: 2

解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"

链接:https://leetcode.cn/problems/delete-operation-for-two-strings/

和之前题目的区别是:现在两个字符串都可以删了。

动规五部曲:
1 确定dp数组以及下标的含义

dp[i][j]以i-1为结尾的字符串word1,和以j-1位结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。

2 确定递推公式

当word1[i - 1] 与 word2[j - 1]相同的时候

当word1[i - 1] 与 word2[j - 1]不相同的时候

当word1[i - 1] 与 word2[j - 1]相同的时候,dp[i][j] = dp[i - 1][j - 1];

当word1[i - 1] 与 word2[j - 1]不相同的时候,有三种情况:

情况一:删word1[i - 1],最少操作次数为dp[i - 1][j] + 1

情况二:删word2[j - 1],最少操作次数为dp[i][j - 1] + 1

情况三:同时删word1[i - 1]和word2[j - 1],操作的最少次数为dp[i - 1][j - 1] + 2

那最后当然是取最小值,所以当word1[i - 1] 与 word2[j - 1]不相同的时候,递推公式:dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

因为 dp[i][j - 1] + 1 = dp[i - 1][j - 1] + 2,所以递推公式可简化为:dp[i][j] = min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);

3 dp数组初始化

从递推公式中可以看出,dp[i][0] 和 dp[0][j]是一定要初始化的。

dp[i][0]:word2为空字符串,以i-1为结尾的字符串word1要删除多少个元素,才能和word2相同呢,很明显dp[i][0] = i。dp[0][j]的话同理。

4 遍历顺序

从上到下,从左到右

5 举例推导dp数组

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int len1=word1.length();
        int len2=word2.length();
        int[][] dp=new int[len1+1][len2+1];

        for(int i=0;i<=len1;i++) dp[i][0]=i;
        for(int j=0;j<=len2;j++) dp[0][j]=j;

        for(int i=1;i<=len1;i++){
            for(int j=1;j<=len2;j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=Math.min(dp[i-1][j]+1,Math.min(dp[i][j-1]+1,dp[i-1][j-1]+2));
                }
            }
        }
        return dp[len1][len2];
    }
}

72编辑距离

题目:给你两个单词word1和word2,请返回将word1 转换成word2所使用的最少操作数。你可以对一个单词进行如下三种操作:插入一个字符,删除一个字符,替换一个字符。

示例 1:输入:word1 = "horse", word2 = "ros",输出:3

解释:horse -> rorse (将 'h' 替换为 'r')

rorse -> rose (删除 'r')

rose -> ros (删除 'e')

链接:https://leetcode.cn/problems/edit-distance/

动规五部曲:
1 确定dp数组及其含义

dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。

2 确定递归公式

两种情况:word1[i - 1] == word2[j - 1]和 word1[i - 1] != word2[j - 1]

if (word1[i - 1] == word2[j - 1]) 那么说明不用任何编辑,dp[i][j] 就应该是 dp[i - 1][j - 1],即dp[i][j] = dp[i - 1][j - 1];

if (word1[i - 1] != word2[j - 1]),就需要编辑了。

操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。即 dp[i][j] = dp[i - 1][j] + 1;

操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。即 dp[i][j] = dp[i][j - 1] + 1;

怎么都是删除元素,添加元素去哪了。word2添加一个元素,相当于word1删除一个元素,例如 word1 = "ad" ,word2 = "a",word1删除元素'd' 和 word2添加一个元素'd',变成word1="a", word2="ad", 最终的操作数是一样。

操作三:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增删加元素。if (word1[i - 1] == word2[j - 1])的时候我们的操作是 dp[i][j] = dp[i - 1][j - 1]。那么只需要一次替换的操作,就可以让 word1[i - 1] 和 word2[j - 1] 相同。所以 dp[i][j] = dp[i - 1][j - 1] + 1;

综上,当 if (word1[i - 1] != word2[j - 1]) 时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;

3 dp数组初始化

dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。

那么dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。那么dp[i][0]就应该是i,对word1里的元素全部做删除操作,即:dp[i][0] = i; 同理dp[0][j] = j。

4 遍历顺序

从左到右从上到下去遍历
5 举例推导dp数组

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int len1=word1.length();
        int len2=word2.length();
        int[][] dp=new int[len1+1][len2+1];

        for(int i=0;i<=len1;i++){
            dp[i][0]=i;
        }
        for(int j=0;j<=len2;j++){
            dp[0][j]=j;
        }

        for(int i=1;i<=len1;i++){
            for(int j=1;j<=len2;j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    dp[i][j]=Math.min(dp[i-1][j]+1,Math.min(dp[i][j-1]+1,dp[i-1][j-1]+1));
                }
            }
        }
        return dp[len1][len2];
    }
}

编辑距离总结

392判断子序列给定字符串 s 和 t ,判断 s 是否为 t 的子序列。

115不同的子序列给定一个字符串 s 和一个字符串 t ,计算在 s 的子序列中 t 出现的个数。

583两个字符串的删除操作给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最少步数,每步可以删除任意一个字符串中的一个字符。

72编辑距离给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数。

相关推荐
陈天伟教授1 小时前
人工智能应用- 人工智能交叉:05. 从 AlphaFold1 到 AlphaFold2
人工智能·神经网络·算法·机器学习·推荐算法
Eloudy2 小时前
直接法 读书笔记 05 第5章 正交方法
人工智能·算法·机器学习
iAkuya2 小时前
(leetcode)力扣100 73柱状图中最大的矩形(单调栈)
算法·leetcode·职场和发展
pp起床2 小时前
动态规划 | part03
算法·动态规划
mit6.8242 小时前
合法括号字符串|递归|树
算法
普通网友2 小时前
C++与Rust交互编程
开发语言·c++·算法
逆境不可逃2 小时前
【春节篇】LeetCode 热题 100 之 238.除了自身以外数组的乘积
数据结构·算法·leetcode
铸人3 小时前
再论自然数全加和 - 质数螺旋及其生成程序
数学·算法·数论·复数
散峰而望3 小时前
【算法竞赛】堆和 priority_queue
开发语言·数据结构·c++·算法·贪心算法·动态规划·推荐算法