代码随想录算法训练营第五十六天 | 583. 两个字符串的删除操作 72. 编辑距离

583. 两个字符串的删除操作

给定两个单词 word1word2 ,返回使得 word1word2 **相同所需的最小步数

每步 可以删除任意一个字符串中的一个字符。

输入: word1 = "sea", word2 = "eat"
输出: 2
解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat "变为 "ea"

这道题和昨天的不同子序列相比,就是两个字符串都可以删除。

动规五部曲:

  1. 确定dp数组及其下标含义

dp[i][j]表示以i-1结尾的字符串word1,以j-1结尾的字符串word2,两个字符串想要相等,所需要删除的元素最少次数。

  1. 确定递推公式

word1[i-1]==word[j-1]dp[i][j]=dp[i-1][j-1]

word[i-1]≠word[j-1]时,分为三种情况:

需要删除word1[i-1],最少操作次数为dp[i-1][j]+1

需要删除word2[j-1],最少操作次数为dp[i][j-1]+1

两个同时删除,最少操作次数为dp[i-1][j-1]+2

dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

  1. dp数组初始化

需要初始化dp[0][j],dp[i][0]

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

同上,dp[0][j]=j

  1. 确定遍历顺序

从前向后遍历

  1. 举例推导dp数组
class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp=new int[word1.length()+1][word2.length()+1];
        for(int i=0;i<=word1.length();i++) dp[i][0]=i;
        for(int j=0;j<=word2.length();j++) dp[0][j]=j;
        for(int i=1;i<=word1.length();i++){
            for(int j=1;j<=word2.length();j++){
                if(word1.charAt(i-1)==word2.charAt(j-1)){
                    dp[i][j]=dp[i-1][j-1];
                }else{
                    int temp=Math.min(dp[i-1][j]+1,dp[i][j-1]+1);
                    dp[i][j]=Math.min(temp,dp[i-1][j-1]+2);
                }
            }
        }
        return dp[word1.length()][word2.length()];

    }
}

72. 编辑距离

给你两个单词 word1word2请返回将 word1 转换成 word2 所使用的最少操作数

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse ('h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

动规五部曲:

  1. dp数组及其下标含义

dp[i][j]表示下标为i-1的word1,和下标j-1的word2想要相等,需要进行的最少操作数

  1. 确定递推公式

word1[i-1]==word[j-1]dp[i][j]=dp[i-1][j-1](不操作)

word[i-1]≠word[j-1]时,分为三种情况:

需要删除word1[i-1],最少操作次数为dp[i-1][j]+1

需要删除word2[j-1],最少操作次数为dp[i][j-1]+1

两个同时删除,最少操作次数为dp[i-1][j-1]+1

dp[i][j] = min({dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

  1. dp数组初始化

dp[i][0] :以下标i-1为结尾的字符串word1,和空字符串word2,最近编辑距离为dp[i][0]。dp[i][0]=i

同上,dp[0][j]=j

  1. 确定遍历顺序

从前向后遍历

  1. 举例推导dp数组
class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp=new int[word1.length()+1][word2.length()+1];
        for(int i=0;i<=word1.length();i++) dp[i][0]=i;
        for(int j=0;j<=word2.length();j++) dp[0][j]=j;

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

    }
}

编辑距离总结

  1. 判断子序列

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

if (s[i - 1] == t[j - 1]) t中找到了一个字符在s中出现了dp[i][j] = dp[i - 1][j - 1] + 1;

if (s[i - 1] != t[j - 1]) t需要删除元素dp[i][j] = dp[i][j - 1];

  1. 不同的子序列

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

if (s[i - 1] == t[j - 1]) 由两部分组成,分别是用s[i-1]来匹配,和不用s[i-1]匹配,dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j];

if (s[i - 1] != t[j - 1]) ,不需要s[i-1]来匹配dp[i][j] = dp[i - 1][j];

  1. 两个字符串的删除操作

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

word1[i-1]==word[j-1]dp[i][j]=dp[i-1][j-1]

word[i-1]≠word[j-1]时,分为三种情况:

需要删除word1[i-1],最少操作次数为dp[i-1][j]+1

需要删除word2[j-1],最少操作次数为dp[i][j-1]+1

两个同时删除,最少操作次数为dp[i-1][j-1]+2

dp[i][j] = min({dp[i - 1][j - 1] + 2, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

  1. 编辑距离

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

  • if (word1[i - 1] == word2[j - 1])
    • 不操作
  • if (word1[i - 1] != word2[j - 1])

word1[i-1]==word[j-1]dp[i][j]=dp[i-1][j-1](不操作)

word[i-1]≠word[j-1]时,分为三种情况:

需要删除word1[i-1],最少操作次数为dp[i-1][j]+1

需要删除word2[j-1],最少操作次数为dp[i][j-1]+1

两个同时删除,最少操作次数为dp[i-1][j-1]+1

dp[i][j] = min({dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1});

你可能感兴趣的:(算法,动态规划)