力扣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];
    }
}
相关推荐
小刘学技术19 小时前
AI人工智能决策树分类器:原理、实现与应用
开发语言·人工智能·python·算法·决策树·机器学习·数据挖掘
天才测试猿19 小时前
Selenium自动化测试网页加载太慢怎么解决?
自动化测试·软件测试·python·selenium·测试工具·职场和发展·测试用例
caimouse20 小时前
mm学习笔记_04:VAD树算法与地址空间分配
笔记·学习·算法·reactos
abcy07121320 小时前
flink窗口类型
开发语言·python·算法
wjm04100620 小时前
ios学习路线 -- objective-c 基础
面试·职场和发展
什巳1 天前
JAVA练习309- 二叉树的层序遍历
java·数据结构·算法·leetcode
什巳1 天前
JAVA练习306- 翻转二叉树
java·数据结构·算法·leetcode
smj2302_796826521 天前
解决leetcode第3989题网格中保持一致的最大列数
python·算法·leetcode
ychqsq1 天前
88.归途
经验分享·职场和发展