题目描述:
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
示例 1:
1 | 输入:word1 = "horse", word2 = "ros" |
示例 2:
1 | 输入:word1 = "intention", word2 = "execution" |
提示:
0 <= word1.length, word2.length <= 500word1和word2由小写英文字母组成
链接:
https://leetcode-cn.com/problems/edit-distance
题目分析
我们需要做的是将 word1 转换到 word2,而每一步操作都只涉及到 1 个字母的变化,一共有 3 种操作,也即插入、替换、删除。其中插入和删除的操作比较难以处理,可能会陷入死循环,有没有办法解决呢?其实 word1 的删除操作和 word2 的插入操作是等价的。比如 abcd -> abc,既可以看做是左边删除了一个 d,变成 abc = abc,也可以视为右边添加了一个 d,变成 abcd = abcd,操作步数都是 1,同样能让两个单词相同。因此我们的方法有以下三种
word1插入一个字符word2插入一个字符word1替换一个字符
注意到以上的操作方法次序对结果是没有影响的,因此我们可以从左到右逐步对字符进行操作,便可以使用动态规划的方法解决。我们逐步分析两个字符串,并保留操作次数最少的方法。dp[i][j] 的值表示 word1 的前 i 个字符与 word2 的前 j 个字符进行匹配需要的最少步数(也即它们的编辑距离)。而每次我们只在字符串的最后进行操作。我们分析状态转移方程,也即 dp[i][j] 的值如何确定。
- 如果最后一步操作是
word1插入字符,也即进行了dp[i][j-1]的操作之后,我们将word2的第j个字符插入到word1最后。 - 如果最后一步操作是
word2插入字符,也即进行了dp[i-1][j]的操作之后,我们将word1的第i个字符插入到word2最后。 - 如果最后一步操作是
word1替换字符,也即进行了dp[i-1][j-1]的操作之后,我们将word1的第i个字符替换为word2的第j个字符(如果这两个字符本来就是相同的,则无需替换)。
以上的三种操作中,我们总是选取操作次数最小的那个作为 dp[i][j] 的值进行状态转移,最后就能够得到 dp[m][n] 也即 word1 转换为 word2 的最少操作数。而边界情况是什么样的?边界情况是其中某一个字符串为空的时候,操作数就是另一个字符串的字符数。也即 dp[0][j] = j,word1 为空时,word1 变为 word2 的操作就是往 word1 插入 j 个字符。同理,dp[i][0] = i。
注意字符串的下标是从 0 开始的,因此 word1 的第 i 个字符是 word1[i-1]。
1 | class Solution { |
时间复杂度:$O(mn)$,其中 $m、n$ 分别是 word1 和 word2 的长度。我们进行了双层遍历。
空间复杂度:$O(mn)$,其中 $m、n$ 分别是 word1 和 word2 的长度。也即动态规划所需的数组大小。