算法练习day48

57 阅读3分钟

一、两个字符串的删除操作

和不同的子序列相比,两个字符串都可以删除了

五部曲

  1. 确定dp数组含义,dp[i][j]以i-1结尾的字符串word1和以j-1结尾的字符串word2,想到达到相等,需要删除元素的最少次数
  2. 确定递推公式
    1. word1[i-1] === word2[j-1], dp[i][j] = dp[i-1][j-1]
    2. word1[i-1] !== word2[j-1],
      1. 删除word1[i-1], dp[i-1][j] + 1
      2. 删除word2[j-1], dp[i][j-1] + 1
      3. 同时删除word1[i-1]word2[j-1]dp[i-1][j-1] + 2
      4. dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 2)
  3. 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
}
  1. 确定遍历顺序,从上到下,从左到右
  2. 举例推导

时间复杂度: 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]
};

二、编辑距离

五部曲

  1. 确定dp数组以及下标的含义,dp[i][j],表示下标为i-1的word1和下标为j-1的word2,最近编辑距离
  2. 确定递推公式
    1. 如果word1[i-1] === word2[j-1],不用任何编辑,dp[i][j] = dp[i-1][j-1]
    2. 如果word1[i-1] !== word2[j-1]
      1. 删除word1一个元素,dp[i-1][j] + 1
      2. 删除word2一个元素,dp[i][j-1] + 1
      3. 替换元素,d[i-1][j-1] + 1
      4. dp[i][j] = Math.min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 1)
  3. 初始化
for(let i = 0; i <= word1.length;i++) {
    dp[i][0] = i
}

for(let j = 0; i <= word2.length;j++) {
    dp[0][j] = j
}
  1. 确定遍历顺序,从上到下,从左到右
  2. 举例推导

时间复杂度: 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]
};