Dynamic Programming学习笔记 (22) - 编辑距离 (力扣# 72)

129 阅读1分钟

编辑距离是双字符串输入的DP应用中的一个经典问题,其题面为

给定两个单词word1和word2,其长度分别为N1和N2, 返回将 word1 转换成 word2 所使用的最少操作数。你可以对一个单词进行如下三种操作:

插入一个字符

删除一个字符

替换一个字符

实例:

word1 = "horse", word2 = "ros"
答案是3,将第一个字符h替换为r,删除第三个字符r,删除最后的e。

解题思路:

我们使用F(i, j)作为DP表达式,其中i和j分别是两个字符串的数组下标,F(i, j)返回的是word1[i:N1]和word2[j:N2]之间的编辑距离。F(i, j)的返回值有以下几种情况,

  1. i>=N1,j>=N2,此时两个字串都为空,F(i, j)返回0
  2. i>=N1,j< N2,此时只有第一个字串为空,因此F(i, j)返回N2 - j个删除
  3. i<N1,j>= N2,此时只有第二个字串为空,因此F(i, j)返回N1 - i个删除
  4. i<N1,j<N2,且word1[i]和word2[j]相同,此时F(i, j)返回F(i + 1, j + 1)
  5. i<N1,j<N2,且word1[i]和word2[j]不同,此时F(i, j)返回以下三个选择中最小的一个
  • 1 + F(i + 1, j + 1), 一个替换
  • 1 + F(i, j + 1), 一个插入
  • 1 + F(i + 1, j), 一个删除

从以上表达式出发,我们使用一个二维的DP数组,以及双重循环,对word1和word2的数组下标分别按从大到小的顺序依次计算DP数组中的各个元素的值,最后DP[0][0]中的数值就是问题的答案。

Java代码如下

class Solution {
    public int minDistance(String word1, String word2) {
        char[] text1 = word1.toCharArray();
        char[] text2 = word2.toCharArray();

        int N1 = text1.length;
        int N2 = text2.length;

        if (N1 == 0) {
            return N2;
        }

        if (N2 == 0) {
            return N1;
        }

        int[][] dp = new int[N1 + 1][N2 + 1];

        for(int i = N1; i >=0; i --) {
            for(int j = N2; j >=0; j --) {
                if (i == N1) {
                    dp[i][j] = N2 - j;
                } else if (j == N2) {
                    dp[i][j] = N1 - i;
                }  else {
                    if (text1[i] == text2[j]) {
                        dp[i][j] = dp[i + 1][j + 1];
                    } else {
                        int min = dp[i + 1][j + 1];

                        min = Math.min(min, dp[i][j + 1]);
                        min = Math.min(min, dp[i + 1][j]);

                        dp[i][j] = min + 1;
                    }
                }
            }
        }

        return dp[0][0];
    }
}