力扣72-编辑距离

给你两个单词 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
  • word1 和 word2 由小写英文字母组成

设 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];
    }
}
相关推荐
Yuzhiyuxia13 小时前
【AI Agent面试系列】AI Agent记忆机制知识点1
人工智能·面试·职场和发展
UIU11413 小时前
P1233 [ICPC 2001 Taejon R] 木棍加工
数据结构·c++·算法·动态规划
论文复现现场14 小时前
WRF、FEA 能用 L40S 加速吗?求解器检查、断点恢复与长期运行
java·数据库·算法·wrf·有限元分析·gpu计算·断点续算
ZhengEnCi14 小时前
用 AI 写代码为什么拼到最后还是拼人:算力瓶颈与领域专家提示词的本质差异
算法·架构
秋天的怀念_David15 小时前
第二十一夜 · 数字黑洞与西西弗斯的惩罚
java·程序人生·算法
碧海银沙音频科技研究院16 小时前
在PC电脑上用Whisper→Marian算法实现离线语音翻译功能
算法·whisper
niyongsheng16 小时前
3D 装箱算法工程化:数据结构、放置启发式与支撑规则
数据结构·算法·rust
j7~18 小时前
【穷举、深搜与回溯算法】一棵决策树讲透全排列与子集
数据结构·c++·算法·leetcode·回溯·递归
傅科摆 _ py19 小时前
DP,贪心,堆和栈,二分力扣复习
开发语言·python·算法
Shaoshing20 小时前
LeetCode100 42.接雨水
java·算法·leetcode