「LeetCode」72-编辑距离

107 阅读1分钟

一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第19天,点击查看活动详情

一.题目:

72. 编辑距离 给你两个单词 word1 和 word2, 请返回将 word1 转换成 word2 所使用的最少操作数  。

你可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符 示例 1:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

示例 2:

输入:word1 = "intention", word2 = "execution"
输出:5
解释:
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')

提示:

  • 0 <= word1.length, word2.length <= 500
  • word1 和 word2 由小写英文字母组成

二、思路分析:

首先这是一道难度为困难的题目,但是如果我们能够仔细审题的话,会发现它的做题思路是很简单的,即利用动态规划进行问题的求解。为什么这道题目需要用到动态规划呢?首先它是一道最值问题,设计最值问题的题目都可以试着利用动态规划进行求解,其次,对单词有可能进行三个操作,三个操作可能产生的效果不同会影响着下一步的结果,从子问题求解到大问题,就是动态规划的基本思路。

明确是用动态规划后,我们需要知道动态规划需要的四个要素

  1. 确定dp数组的具体含义,我们设定的dp数组为dp[i][j],dp[i][j]表示word10iword20j的最少操作数
  2. 对dp数组进行必要的初始化,我们知道word1或者word2只要其中一个是空字符的时候,另一个的操作数就是它的长度,所以我们利用这一点进行初始化
  3. 明确状态转移方程:如果i,j前一位的字符相等时,我们就不需要进行处理直接赋值即可,因为我们不需要对其进行操作就能够符合要求,如果不是相等的话,我们明确对元素处理只有三个操作:插入、删除和替换,插入和删除实际的代码也是一样的,明确要么是word1中的单词字符需要插入或者删除或者word2中的单词字符需要插入或者删除,替换我们对任意一个单词的字符进行替换即可,然后比较得出最小值赋值给dp[i][j]
  4. 明确遍历顺序,我们由下图得知dp[i][j]由上方,左方和左上决定,所以我们的遍历顺序就是从左到右从上到小的顺序。

image.png

三、代码:

/**
 * @param {string} word1
 * @param {string} word2
 * @return {number}
 */
var minDistance = function (word1, word2) {
    let m = word1.length
    let n = word2.length
    //1.确定dp的大小及其含义:dp[i][j]表示word1中0到i与word2中0到j的最少操作数
    let dp = Array.from(new Array(m+1), () => new Array(n+1).fill(0))
    //2.明确初始化:我们知道word1或者word2其中一个是空字符的时候,另一个的操作数就是它的长度
    for (let i = 0; i <= m; i++) {
        dp[i][0] = i
    }
    for (let j = 0; j <= n; j++) {
        dp[0][j] = j
    }
    //3.明确状态转移方程   插入、删除、替换
    //4.有状态方程确定遍历顺序:从上到下,从左到右
    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; 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[m][n]
};

四、总结:

如果不熟悉动态规划的话,解决这类问题是很困难的,如果使用暴力算法那么必超时,所以学习动态规划,了解四要素还是很有必要的。