开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第25天,点击查看活动详情
583. 两个字符串的删除操作 题目描述:给定两个单词 word1 和 word2 ,返回使得 word1 和 word2 相同所需的最小步数。每步 可以删除任意一个字符串中的一个字符。提示 1 <= word1.length, word2.length <= 500、word1 和 word2 只包含小写英文字母。
| 示例1 | 示例2 |
|---|---|
输入: word1 = "sea", word2 = "eat" 输出: 解释: 第一步将 "sea" 变为 "ea" ,第二步将 "eat" 变为 "ea" | 输入:word1 = "leetcode", word2 = "etco" 输出: |
中规中矩的动态规划
关于编辑距离问题,之前已经介绍过 # 115. 不同的子序列、# 392. 判断子序列 两篇,这一题又是一个典型的编辑距离问题,只是两个字符串上的字符都可以进行删除操作。
1、确定 dp 状态数组
定义 是以 字符结尾的 word1 和 以 字符结尾的 word2,使其相等时,需要删除元素的最小次数,其中 ,。
2、确定 dp 状态方程
依然要讨论 与 是否相等:
当 时,两字符相同说明不需要删除,以 字符结尾的 word1 和 以 字符结尾的 word2 相等时需要删除元素的最小次数 应该与以 字符结尾的 word1 和 以 字符结尾的 word2 相等时需要删除元素的最小次数 相等,即,
当 时,
-
如果仅删除 ,以 字符结尾的
word1和 以 字符结尾的word2相等时需要删除元素的最小次数 ,应该比以 字符结尾的word1和 以 字符结尾的word2相等时需要删除元素的最小次数 多 ,即 ; -
如果仅删除 ,以 字符结尾的
word1和 以 字符结尾的word2相等时需要删除元素的最小次数 ,应该比以 字符结尾的word1和 以 字符结尾的word2相等时需要删除元素的最小次数 多 ,即 ; -
如果 、 都删除,以 字符结尾的
word1和 以 字符结尾的word2相等时需要删除元素的最小次数 ,应该比以 字符结尾的word1和 以 字符结尾的word2相等时需要删除元素的最小次数 多 (要删除两次嘛),即 ;
综上所述,当 时,
3、确定 dp 初始状态
-
初始化规模为 ,且各个元素为 ;
-
为第 列哨兵节点,代表
word2是空字符串时,以 结尾的word1要与word2相等,删除元素的最小次数,即 ; -
为第 行哨兵节点,代表
word1是空字符串时,以 结尾的word2要与word1相等,删除元素的最小次数,即 ;
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] + 1, dp[i - 1][j - 1] + 2);
}
}
}
return dp[len1][len2];
};