一、两个字符串的删除操作
和不同的子序列相比,两个字符串都可以删除了
五部曲
- 确定dp数组含义,
dp[i][j]以i-1结尾的字符串word1和以j-1结尾的字符串word2,想到达到相等,需要删除元素的最少次数 - 确定递推公式
- 当
word1[i-1] === word2[j-1],dp[i][j] = dp[i-1][j-1] - 当
word1[i-1] !== word2[j-1],- 删除
word1[i-1],dp[i-1][j] + 1 - 删除
word2[j-1],dp[i][j-1] + 1 - 同时删除
word1[i-1]和word2[j-1],dp[i-1][j-1] + 2 dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2)
- 删除
- 当
- dp数组初始化
for(let i = 0; i <= word1.length;i++) {
dp[i][0] = i
}
for(let j = 0; i <= word2.length;j++) {
dp[0][j] = j
}
- 确定遍历顺序,从上到下,从左到右
- 举例推导
时间复杂度: O(n * m) 空间复杂度: O(n * m)
/**
* @param {string} word1
* @param {string} word2
* @return {number}
*/
var minDistance = function (word1, word2) {
let dp = new Array(word1.length + 1).fill(0).map(_ => new Array(word2.length + 1).fill(0))
for (let i = 0; i <= word1.length; i++) {
dp[i][0] = i
}
for (let j = 0; j <= word2.length; j++) {
dp[0][j] = j
}
for (let i = 1; i <= word1.length; i++) {
for (let j = 1; j <= word2.length; 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)
}
}
}
return dp[word1.length][word2.length]
};
思路二
只要求出两个字符的最长公共子序列长度即可,然后用两个字符串的总长度减去两个最长公共子序列的长度即可
时间复杂度: O(n * m) 空间复杂度: O(n * m)
var minDistance = function (word1, word2) {
let dp = new Array(word1.length + 1).fill(0).map(_ => new Array(word2.length + 1).fill(0))
for (let i = 1; i <= word1.length; i++) {
for (let j = 1; j <= word2.length; j++) {
if (word1[i - 1] === word2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1
} else {
dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1])
}
}
}
return word1.length + word2.length - 2 * dp[word1.length][word2.length]
};
二、编辑距离
五部曲
- 确定dp数组以及下标的含义,
dp[i][j],表示下标为i-1的word1和下标为j-1的word2,最近编辑距离 - 确定递推公式
- 如果
word1[i-1] === word2[j-1],不用任何编辑,dp[i][j] = dp[i-1][j-1] - 如果
word1[i-1] !== word2[j-1]- 删除word1一个元素,
dp[i-1][j] + 1 - 删除word2一个元素,
dp[i][j-1] + 1 - 替换元素,
d[i-1][j-1] + 1 dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 1)
- 删除word1一个元素,
- 如果
- 初始化
for(let i = 0; i <= word1.length;i++) {
dp[i][0] = i
}
for(let j = 0; i <= word2.length;j++) {
dp[0][j] = j
}
- 确定遍历顺序,从上到下,从左到右
- 举例推导
时间复杂度: O(n * m) 空间复杂度: O(n * m)
/**
* @param {string} word1
* @param {string} word2
* @return {number}
*/
var minDistance = function (word1, word2) {
let dp = new Array(word1.length + 1).fill(0).map(_ => new Array(word2.length + 1).fill(0))
for (let i = 0; i <= word1.length; i++) {
dp[i][0] = i
}
for (let j = 0; j <= word2.length; j++) {
dp[0][j] = j
}
for (let i = 1; i <= word1.length; i++) {
for (let j = 1; j <= word2.length; 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] + 1)
}
}
}
return dp[word1.length][word2.length]
};