两个字符串的删除操作
js
// 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
// 示例:
// 输入: "sea", "eat"
// 输出: 2
// 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"
function fn(word1, word2) {
// dp[i][j] 表示以 i-1 结尾的word1和以 j-1 结尾的word2 最小步数
const w1Len = word1.length, w2Len = word2.length, dp = new Array(w1Len + 1).fill(0).map(() => new Array(w2Len + 1).fill(0))
// 初始化:空字符串与单词比较,最小步数就应该是单词的长度
for(let i = 0; i <= w1Len; i ++) {
dp[i][0] = i
}
for(let i = 0; i <= w2Len; i ++) {
dp[0][i] = i
}
for(let i = 1; i <= w1Len; i ++) {
for(let j = 1; j <= w2Len; j ++){
if(word1[i - 1] === word2[j - 1]){
// 相等,不需要操作
dp[i][j] = dp[i - 1][j - 1]
} else {
// 不相等,可以删除word1,也可以删除word2,还可以两个都删除,求一个最小值
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 2)
}
}
}
console.table(dp);
return dp[w1Len][w2Len]
}
// todo:思路2,求出最长子序列,然后word1+word2减去子序列长度,就得到最小操作步数
function fn1(word1, word2){
const w1Len = word1.length, w2Len = word2.length, dp = new Array(w1Len + 1).fill(0).map(() => new Array(w2Len + 1).fill(0))
let res = 0
for(let i = 1; i <= w1Len; i ++){
for(let j = 1; j <= w2Len; 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])
}
res = Math.max(dp[i][j], res)
}
}
return (w1Len + w2Len) - 2 * res
}
console.log(fn("sea","eat"))
console.log(fn1("sea","eat"))
// ┌─────────┬───┬───┬───┬───┐
// │ (index) │ 0 │ 1 │ 2 │ 3 │
// ├─────────┼───┼───┼───┼───┤
// │ 0 │ 0 │ 1 │ 2 │ 3 │
// │ 1 │ 1 │ 2 │ 3 │ 4 │
// │ 2 │ 2 │ 1 │ 2 │ 3 │
// │ 3 │ 3 │ 2 │ 1 │ 2 │
// └─────────┴───┴───┴───┴───┘
console.log(fn("sea","sea"))
console.log(fn1("sea","sea"))// 给定两个单词 word1 和 word2,找到使得 word1 和 word2 相同所需的最小步数,每步可以删除任意一个字符串中的一个字符。
// 示例:
// 输入: "sea", "eat"
// 输出: 2
// 解释: 第一步将"sea"变为"ea",第二步将"eat"变为"ea"
function fn(word1, word2) {
// dp[i][j] 表示以 i-1 结尾的word1和以 j-1 结尾的word2 最小步数
const w1Len = word1.length, w2Len = word2.length, dp = new Array(w1Len + 1).fill(0).map(() => new Array(w2Len + 1).fill(0))
// 初始化:空字符串与单词比较,最小步数就应该是单词的长度
for(let i = 0; i <= w1Len; i ++) {
dp[i][0] = i
}
for(let i = 0; i <= w2Len; i ++) {
dp[0][i] = i
}
for(let i = 1; i <= w1Len; i ++) {
for(let j = 1; j <= w2Len; j ++){
if(word1[i - 1] === word2[j - 1]){
// 相等,不需要操作
dp[i][j] = dp[i - 1][j - 1]
} else {
// 不相等,可以删除word1,也可以删除word2,还可以两个都删除,求一个最小值
dp[i][j] = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1, dp[i - 1][j - 1] + 2)
}
}
}
console.table(dp);
return dp[w1Len][w2Len]
}
// todo:思路2,求出最长子序列,然后word1+word2减去子序列长度,就得到最小操作步数
function fn1(word1, word2){
const w1Len = word1.length, w2Len = word2.length, dp = new Array(w1Len + 1).fill(0).map(() => new Array(w2Len + 1).fill(0))
let res = 0
for(let i = 1; i <= w1Len; i ++){
for(let j = 1; j <= w2Len; 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])
}
res = Math.max(dp[i][j], res)
}
}
return (w1Len + w2Len) - 2 * res
}
console.log(fn("sea","eat"))
console.log(fn1("sea","eat"))
// ┌─────────┬───┬───┬───┬───┐
// │ (index) │ 0 │ 1 │ 2 │ 3 │
// ├─────────┼───┼───┼───┼───┤
// │ 0 │ 0 │ 1 │ 2 │ 3 │
// │ 1 │ 1 │ 2 │ 3 │ 4 │
// │ 2 │ 2 │ 1 │ 2 │ 3 │
// │ 3 │ 3 │ 2 │ 1 │ 2 │
// └─────────┴───┴───┴───┴───┘
console.log(fn("sea","sea"))
console.log(fn1("sea","sea"))