开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第26天,点击查看活动详情
72. 编辑距离 题目描述:给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数。你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
| 示例1 | 示例2 |
|---|---|
输入:word1 = "horse", word2 = "ros" 输出: 解释: 第步: horse -> rorse (将 'h' 替换为 'r') 第步: rorse -> rose (删除 'r') 第步: rose -> ros (删除 'e') | 输入:word1 = "intention", word2 = "execution" 输出: 解释: 第步: intention -> inention (删除 't') 第步: inention -> enention (将 'i' 替换为 'e') 第步: enention -> exention (将 'n' 替换为 'x') 第步: exention -> exection (将 'n' 替换为 'c') 第步: exection -> execution (插入 'u') |
中规中矩的动态规划
这一道是完全意义上的编辑距离问题。之前已经更新过三篇入门级别的有关编辑距离问题的题解,
1、确定 dp 状态数组
定义 是以 结尾的 word1 子序列和以 结尾的 word2 子序列的最小编辑距离,其中 ,。
2、确定 dp 状态方程
判断 和 的关系:
当 时,以 结尾的 word1 子序列和以 结尾的 word2 子序列的最小编辑距离,即 ,应等于以 结尾的 word1 子序列和以 结尾的 word2 子序列的最小编辑距离,即
当 时,此时可以选择执行插入、删除、替换三种操作之一:
-
如果删除一个元素(从
word1的子序删除),以 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,应比 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,多 ,此时 ; -
同理,如果删除一个元素(从
word2的子序删除),以 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,应比 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,多 ,此时 ; -
如果增加一个元素(从
word1的子序增加),以 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,应比 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,多 ,此时 ;(从word1增加元素就如同从word2删除元素) -
同理,如果增加一个元素(从
word2的子序增加),以 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,应比 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,多 ,此时 ;(从word2增加元素就如同从word1删除元素) -
替换元素,此时不需要增加/删除元素,以 结尾的
word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,应比 结尾的word1子序列和以 结尾的word2子序列的最小编辑距离,即 ,多 ,此时 ;
综上所述, 时,
3、确定 dp 初始状态
-
声明规模为 ,且元素均为 的数组;
-
为以 结尾的
word1子序列和空字符串的最小编辑距离,即 ; -
为空字符串和以 结尾的
word2子序列的最小编辑距离,即 ;
4、确定遍历顺序
-
外层循环遍历
word1,从 到 ; -
内层循环遍历
word2,从 到 。
5、确定最终返回值
回归到状态定义中,即 。
6、代码示例
/**
* 空间复杂度 O(word1.length * word2.length)
* 时间复杂度 O(word1.length * word2.length)
*/
function minDistance(word1: string, word2: string): number {
const len1 = word1.length;
const len2 = word2.length;
const dp = Array.from({ length: len1 + 1 }, () => new Array(len2 + 1).fill(0));
for (let i = 0; i <= len1; i++) {
dp[i][0] = i;
}
for (let j = 0; j <= len2; j++) {
dp[0][j] = j;
}
for (let i = 1; i <= len1; i++) {
for (let j = 1; j <= len2; j++) {
if (word1[i - 1] === word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1];
} else {
dp[i][j] = Math.min(dp[i - 1][j - 1], dp[i][j - 1], dp[i - 1][j]) + 1;
}
}
}
return dp[len1][len2];
};