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

97 阅读3分钟

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

题目链接:583. 两个字符串的删除操作

思路:直接动态规划五步曲。

  1. dp[i][j]:以i-1为结尾的字符串word1,和以j-1为结尾的字符串word2,想要达到相等,所需要删除元素的最少次数。
  2. 递推公式分情况讨论

当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][j] = dp[i - ][j] + 1;
  • 删除word2[j - 1],此时dp[i][j] = dp[i][j - 1] + 1;
  • 同时删word1[i - 1]和word2[j - 1],此时dp[i][j] = dp[i - 1][j - 1] + 2
  1. 初始化,dp[i][0]代表当word2为空串式,word1要删除的元素个数,很明显,dp[i][0] = i,dp[0][j]也是同理。
  2. 遍历顺序,由递推公式我们可知道,需要从上到小,从左到右遍历。
  3. 举例说明

这里使用的代码和思路分析中的代码有所差别,

代码中是将问题转换成了求解的共子序列问题然后来求解。

class Solution {
    public int minDistance(String word1, String word2) {
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];

        char[] arr1 = word1.toCharArray();
        char[] arr2 = word2.toCharArray();
        for (int i = 1; i <= arr1.length; i++) {
            for (int j = 1; j <= arr2.length; j++) {
                if (arr1[i - 1] == arr2[j - 1]) {
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                } else {
                    dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        return arr1.length + arr2.length - 2 * dp[arr1.length][arr2.length];
    }
}

72. 编辑距离

题目链接:72. 编辑距离

思路:本题是经典的编辑距离问题,使用动规非常巧妙,动态规划五步曲分析:

  1. dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
  2. 递推公式:分情况讨论

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][j] = dp[i - 1][j] + 1
  • 删除word2[j - 1],此时dp[i][j] = dp[i][j - 1] + 1(注意这里没有增加操作,因为删除word1就相当于增加word2,删除word2就相当于增加word1,不要重复累计
  • 替换一个元素,此时dp[i][j] = dp[i - 1][j - 1] + 1
  1. 初始化,本题初始化原理与上一题相同。
  2. 遍历顺序为从上到下从左到右遍历
  3. 举例说明
class Solution {
    public int minDistance(String word1, String word2) {
        // dp[i][j] 表示下标为i-1结尾的word1和下标为j-1结尾的word2的最近编辑距离。
        int[][] dp = new int[word1.length() + 1][word2.length() + 1];

        char[] arr1 = word1.toCharArray();
        char[] arr2 = word2.toCharArray();
        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 <= arr1.length; i++) {
            for (int j = 1; j <= arr2.length; j++) {
                if (arr1[i - 1] == arr2[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 - 1][j], dp[i][j - 1])) + 1;
                }
            }
        }
        return dp[arr1.length][arr2.length];
    }
}

编辑距离总结

从判断子序列开始,都是编辑距离的问题,前三道题目依次递进,为最后编辑距离的问题做了很好的铺垫。