思路
dp[i][j] 表示以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
递推公式:
if (word1[i - 1] == word2[j - 1]) 不操作
if (word1[i - 1] != word2[j - 1]) 增 删 换
——————————————————————————————————————————————————————-
if (word1[i - 1] != word2[j - 1]),此时就需要编辑了,如何编辑呢?
- 操作一:word1删除一个元素,那么就是以下标i - 2为结尾的word1 与 j-1为结尾的word2的最近编辑距离 再加上一个操作。
即 dp[i][j] = dp[i - 1][j] + 1;
- 操作二:word2删除一个元素,那么就是以下标i - 1为结尾的word1 与 j-2为结尾的word2的最近编辑距离 再加上一个操作。
即 dp[i][j] = dp[i][j - 1] + 1;
这里有同学发现了,怎么都是删除元素,添加元素去哪了。
word2添加一个元素,相当于word1删除一个元素,例如 word1 = “ad” ,word2 = “a”,word1删除元素’d’ 和 word2添加一个元素’d’,变成word1=”a”, word2=”ad”, 最终的操作数是一样!【它们是等价的,即你可以把所有的删除操作 转换成 增加操作】
- 操作三:替换元素,word1替换word1[i - 1],使其与word2[j - 1]相同,此时不用增加元素,那么以下标i-2为结尾的word1 与 j-2为结尾的word2的最近编辑距离 加上一个替换元素的操作。
综上,当 if (word1[i - 1] != word2[j - 1]) 时取最小的,即:dp[i][j] = min({dp[i - 1][j - 1], dp[i - 1][j], dp[i][j - 1]}) + 1;
var minDistance = function(word1, word2) {
// 思路太绝了,我只会模仿
// dp[i][j]:以下标i-1为结尾的字符串word1,和以下标j-1为结尾的字符串word2,最近编辑距离为dp[i][j]。
// 编辑操作:增、删、改
// 核心难点:增加操作和删除操作其实本质是相同的
let len1 =word1.length
let len2 =word2.length
let dp =new Array(len1+1).fill().map(()=>new Array(len2+1).fill(0))
// 一方为空字符串时,编辑操作就是删除,所以初始化为i
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],dp[i][j-1],dp[i-1][j-1]) +1
}
}
}
return dp[len1][len2]
};