前言
编辑距离,经典的动态规划问题,在leetcode72题,属于困难题目。编辑距离主要的困难在于思考如何去进行状态的转移与选择。接下来,我们将一步一步分析,解决编辑距离的相关问题。
题目描述
给你两个单词 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 由小写英文字母组成
思路分析
编辑距离问题就是给定了两个字符串word1,word2,只能使用三种操作即删除、插入、替换,将word1变成word2,求最少的操作数。其中,word1和word2两者之间的变换,无论是word1变换为Word2还是word2变换成word1,最短的编辑距离应该都是一样的。 因此,我们只需要考虑其中一种变换就可
解决双字符串动态规划问题,一般使用双指针i,j
分别指向两个字符串的串尾,随后不断往前往前缩减,缩小问题的规模
接下来,我们简单看一下示例1中word1怎么转换为word2的
word1 = "horse", word2 = "ros"
word1: h o r s e
word2: r o s
================
1:
i
word1: h o r s e
word2: r o s
j
word1[i] != word2[j] 删除word1[j] i-- (第一次操作)
================
2:
i
word1: h o r s
word2: r o s
j
word1[i] == word2[j] 跳过,i--,j--
=================
3:
i
word1: h o r s
word2: r o s
j
word1[i] != word2[j] 删除word1[i],i-- (第二次操作)
==================
4:
i
word1: h o s
word2: r o s
j
word1[i] == word2[j] 跳过,i--,j--
==================
5:
i
word1: h o s
word2: r o s
j
word1[i] != word2[j] 替换word1[i],i--,j-- (第三次操作)
===================
6:
i
word1: r o s
word2: r o s
j
word1[i] != word2[j] 跳过,i--,j--
===================
i < 0 , j < 0 结束
根据上述步骤,我们发现其实字符串转换过程中,不止包含三个操作,其实还有第4个操作【跳过】
,即什么都不做。因为本身两个字符已经相同了,而我们为了使编辑距离尽可能的小,因此应该尽可能的补缺改动本来相同的字符。
另外除了上述可能的情况外,我们还需要考虑一个问题:i或者j提前走完了。也就是说,其中一方多了部分字符串,此时只能采用删除或者插入方法不断的缩减两个字符串之间的差距。看下方示例:
i
word1: a r o s
word2: r o s
j
上述两种i,j 提前走后属于是算法的base case
初步代码
动态规划 递归等常用方法,都需要考虑base case情况。在上述介绍中,我们了解到base case就是 i 走完word1,或者j走完s2,可以直接返回另一个字符出剩下的长度。
同时,对于每对字符是word1[i] 和 word2[j] ,存在4中操作方式:
if (word1[i] == word2[j]){
skip;
i++;j++;
}else{
三选一:
insert,
delete,
replace
}
针对这个代码框架,我们再来确定一下动态规划所必须的要素:状态以及选择。 状态即i,j位置,选择则是4种操作skip,insert,delete,replace。
这里先提供算法代码,后面会对代码进行详细解释:
//dp函数的定义
//s1[0..i] 和 s1[0..j]的最小编辑距离是dp(i,j)
int dp(string s1,string s2,int i,