题目描述:
给你两个单词 word1
和 word2
,请你计算出将 word1
转换成 word2
所使用的最少操作数。
你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
示例 1:
1 | 输入:word1 = "horse", word2 = "ros" |
示例 2:
1 | 输入:word1 = "intention", word2 = "execution" |
提示:
0 <= word1.length, word2.length <= 500
word1
和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
的长度。也即动态规划所需的数组大小。