力扣72-编辑距离

给你两个单词 word1word2请返回将 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 由小写英文字母组成

dp[i][j] 表示的是:将 word1 的前 i 个字符,转换为 word2 的前 j 个字符,所需要的编辑距离(即最小操作数)

两种情况:字符相等与字符不相等

情况一:字符相等

word1 的第 i 个字符 word1[i - 1] 等于 word2 的第 j 个字符 word2[j - 1],那么不需要做任何编辑操作,此时 dp[i][j] = dp[i - 1][j - 1]

情况二:字符不等

考虑三种编辑操作:

替换

word1[i - 1] 替换为 word2[j - 1],此时最后一个字符相同,操作数加一,即 dp[i][j] = dp[i - 1][j - 1] + 1

插入

在 word1 中插入word2[j - 1],由于此时 word1 的长度变为 i + 1,那么相当于将 word1 的前 i 个字符转换为 word2 的前 j - 1 个字符后,再插入一个字符,即dp[i][j] = dp[i][j - 1] + 1

删除

从 word1 中删除 word1[i - 1],由于此时 word1 的长度变为 i - 1,那么相当于将 word1 的前 i - 1个字符转换为 word2 的前 j 个字符,即 dp[i][j] = dp[i - 1][j] + 1

最终,应该取这三种情况的最小值

边界情况

如果有一个串为空串,另一个串不为空串且长度为 k,那么只需要执行 k 次删除操作或增加操作即可

所以 dp[i][0] = i, dp[0][j] = j

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int n = word1.length();
        int m = word2.length();
        if(n * m == 0) {
            // 如果有空串,只需执行 n 或 m 次删除或添加操作
            return n + m;
        }

        int[][] dp = new int[n + 1][m + 1];
        for(int i = 0; i < n + 1; i++) {
            dp[i][0] = i;
        }
        for(int j = 0; j < m + 1; j++) {
            dp[0][j] = j;
        }

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

可以将 dp 数组简化为一个两行数组,因为dp[i][j]只和它左上、左边、上方的元素相关

再进一步,也可以只用一个一维数组

java 复制代码
class Solution {
    public int minDistance(String word1, String word2) {
        int m = word2.length();
        char[] w2 = word2.toCharArray();

        int[] dp = new int[m + 1];
        for(int j = 0; j < m; j++) {
            // dp[0] 相当于 dp[i][0], 值为 i , 因此这里不做初始化,遍历 word1 再处理
            dp[j + 1] = j + 1;
        }

        for(char ch : word1.toCharArray()) {
            int pre = dp[0]; // 每次当 j = 0,dp[i][1] 的 左上角就是 dp[i - 1][0]
            dp[0]++; // 每遍历一个 word1[i - 1], dp[i][0]都更新为 i , 这里由于是一维数组,因此值自增就表示值为 i
            for(int j = 0; j < m; j++) {
                int tmp = dp[j + 1];
                if(ch == w2[j]) {
                    dp[j + 1] = pre;
                } else {
                    // pre 表示左上角,dp[j + 1] 表示上方,dp[j] 表示左边
                    dp[j + 1] = Math.min(Math.min(dp[j + 1], dp[j]), pre) + 1;
                }
                pre = tmp;
            }
        }

        return dp[m];
    }
}
相关推荐
.道阻且长.5 小时前
2.LeetCode算法习题讲解--双指针--复写零
算法·leetcode·职场和发展
To_OC7 小时前
LC 438 找到所有字母异位词:暴力超时后,我靠滑动窗口一招搞定
javascript·算法·leetcode
Forever Nore10 小时前
学完C语言力扣第一题做不来正常吗
数据结构·算法
hansang_IR10 小时前
【题解】LC:倍增 / 区间并查集(Range Parallel Unionfind)
c++·算法·并查集
Tisfy12 小时前
LeetCode 3731.找出缺失的元素:哈希 / 排序
算法·leetcode·哈希算法·排序·哈希表
lucas_AI12 小时前
Q-CueGraph:你的多模态大模型会 zoom,但真的知道该看哪儿吗?
人工智能·算法
kaixin_啊啊12 小时前
test_机器学习算法学习
学习·算法·机器学习
liulilittle12 小时前
MOE路由:路由(logits: top-k/8)
c++·人工智能·算法·机器学习·llm
旖旎夜光13 小时前
LeetCode 11:盛最多水的容器(双指针问题) —— 题解
数据结构·c++·算法·leetcode·双指针