Leetcode72. 编辑距离

145 阅读2分钟

要求:

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

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

插入一个字符
删除一个字符
替换一个字符

示例:

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

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

要求:

对于两个字符串,以一个为基准,另一个向它靠齐。都是先指向各自的最后一个元素,从尾至头的遍历。

  • base case:某个字符串的长度全部走完了,那么直接返回另一个字符串剩下的长度即可。

  • 选择:插入(dp(i,j-1)+1);删除(dp(i-1,j)+1);替换(dp(i-1,j-1)+1)

  • 返回值:dp(len(s1)-1, len(s2)-1);

  • 状态转换:

    1. 插入时:在s1中插入一个和s2中某个元素一样的字母,那么s2就相当于是匹配成功了,前移,但是i还是在原地不动。所以是dp(i,j-1)+1。
    2. 删除时:直接把s1中的这个字母删除,不管是否匹配,所以i前移,j不变
    3. 替换时:两个都变,所以i,j都减一
  • dp状态表格:创建数组dp[s1.length+1][s2.length+1]来记录,避免不断重复计算路径。一般设计的时候都会是这样,行列都是各自长度加一,这样可以把第一行第一列作为基础值先设置一下,最后返回的时候索引是正常的,在循环中的索引一般都是从1开始。

  • 三种状态的选择,哪一种是最优并不清楚,那么就选其中的最小值,三个都走一遍。

    借用大佬labuladong的图,紫色部分都是初始设定时给定的值。

代码

class Solution {
    public int minDistance(String word1, String word2) {
        int m = word1.length();
        int n = word2.length();
        int[][] dp = new int[m+1][n+1];
        for (int i = 0; i < m+1; i++) {
            dp[i][0] = i;
        }
        for (int i = 0; i < n+1; i++) {
            dp[0][i] = i;
        }
        for (int i = 1; i < m+1; i++) {
            for (int j = 1; j < n+1; j++) {
                if (word1.charAt(i-1) == word.charAt(j-1)) {
                    dp[i][j] = dp[i-1][j-1];
                } else {
                    dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1);
                }
            }
        }
        return dp[m][n];
    }
    public int min(int a, int b, int c) {
        return Math.min(a, Math.min(b,c));
    }
}