给你两个单词 word1
和 word2
, 请返回将 word1
转换成 word2
所使用的最少操作数 。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
这道题也是,一眼动态规划,乍一看感觉很复杂,仔细思考一下还是觉得很复杂。
这道题的dp【i】【j】含义我们设定为:word1的前 i 字符串转变为word2的前 j 字符串所需要进行的最小操作数。
当word1
和word2
中的一个为空时,即从空字符串变成另一个字符串或者从一个字符串变为空,转换所需的操作数即为另一个单词的长度。
逐一遍历word1的每个字符上遍历word2的每个字符。
当word【i】=word【j】时,无需做改变。
当word【i】!=word【j】时,我们有三种操作选择,增加/删除/替换;这三种情况对应着不同的前置情况。
我们用代码来实现思路:
对于两个单词word1
和word2
,设dp[i][j]
表示word1
的前i
个字符转换成word2
的前j
个字符所使用的最少操作数。我们想要计算的最终结果是dp[m][n]
,其中m
和n
分别是word1
和word2
的长度。
-
初始化:当
word1
和word2
中的一个为空时,转换所需的操作数即为另一个单词的长度。因此,dp[i][0] = i
(0<=i<=m
)和dp[0][j] = j
(0<=j<=n
)。 -
状态转移方程:
- 如果
word1[i-1] == word2[j-1]
(注意dp
数组的下标从1开始计数,而字符串的下标从0开始),则dp[i][j] = dp[i-1][j-1]
,因为最后一个字符相同,不需要额外操作。 - 如果
word1[i-1] != word2[j-1]
,则需要考虑三种操作:- 插入:
dp[i][j-1] + 1
- 删除:
dp[i-1][j] + 1
- 替换:
dp[i-1][j-1] + 1
- 插入:
- 取这三种操作的最小值作为
dp[i][j]
。
- 如果
var minDistance = function(word1, word2) {
const l1=word1.length;
const l2=word2.length;
const dp=new Array(l1+1).fill(0).map(()=>new Array(l2+1).fill(0))
for(var i=1;i<=l1;i++)dp[i][0]=dp[i-1][0]+1;//初始化遍历各种长度的word1变成空字符串的步数(只能靠不断删除)
for(var i=1;i<=l2;i++)dp[0][i]=dp[0][i-1]+1;//初始化遍历空字符串长度的word1变成word2的各种长度需要的部署(只能靠不断插入)
//填表
for(var i=1;i<=l1;i++){
for(var j=1;j<=l2;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[l1][l2];//输出l1长度的word1(即word1)变换成l2长度的word2(即word2)所需要的最小操作数
};