原题
动态规划困难1 种解法

#72编辑距离

计算把 word1 转换为 word2 所需的最少插入、删除或替换次数。

#字符串#动态规划

原题

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

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

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

示例 1:

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

示例 2:

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

提示:

  • 0 <= word1.length, word2.length <= 500
  • word1word2 由小写英文字母组成

查看原题

解题主线

  1. dp[i][j] 表示 word1 前 i 个字符转换为 word2 前 j 个字符的最少操作数。
  2. 末字符相同则直接继承 dp[i - 1][j - 1];否则从替换、删除、插入三个前驱状态中取最小值再加一。
  3. 额外的第 0 行和第 0 列表示空串,使边界分别初始化为连续插入和连续删除的次数。

解法 1:二维前缀动态规划

按前缀长度从小到大填表,为每对前缀选择末字符匹配或三种编辑操作中的最优转移。

  • 时间复杂度: O(mn),m、n 分别为两个字符串长度

  • 空间复杂度: O(mn)

JAVA
final class Solution {
    public int minDistance(String word1, String word2) {
        if (word1 == null || word2 == null) {
            throw new IllegalArgumentException("words must not be null");
        }

        int m = word1.length();
        int n = word2.length();
        // dp[i][j] 表示两个长度分别为 i、j 的前缀之间的最小编辑次数
        int[][] dp = new int[m + 1][n + 1];
        // 与空串互转时,只能连续删除或连续插入
        for (int i = 0; i <= m; i++) dp[i][0] = i;
        for (int j = 0; j <= n; j++) dp[0][j] = j;

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                // 末字符相同无需操作,直接继承去掉两端后的状态
                if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    // 三个前驱分别对应替换、删除 word1 末字符和插入目标末字符
                    int replace = dp[i - 1][j - 1];
                    int delete = dp[i - 1][j];
                    int insert = dp[i][j - 1];
                    dp[i][j] = Math.min(replace, Math.min(delete, insert)) + 1;
                }
            }
        }
        return dp[m][n];
    }
}

边界与易错点

  • 字符串下标是 i - 1、j - 1,而 DP 下标是前缀长度 i、j,不能混用。
  • dp[i - 1][j] 对应删除 word1 末字符,dp[i][j - 1] 对应向 word1 插入 word2 末字符。
  • 两个末字符相等时不需要加一,否则会高估答案。

整理来源

由旧仓库源码复核、去重并整理;展示代码已按 Java 21 语义修正明显问题。

  • leetcode/src/main/java/zhard/Q072_char_distance.java