问题描述
给你两个单词 word1 和 word2,请你计算出将 word1 转换成 word2 所使用的最少操作数 。你可以对一个单词进行如下三种操作:
- 插入一个字符
- 删除一个字符
- 替换一个字符
示例:
输入:word1 = "horse", word2 = "ros"
输出:3
解释:
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')
分析问题
根据题目要求,你可以对任意一个单词进行增、删、改三种操作,题目给定两个单词,所以一共有2*3=6中操作。但是这里包含了一些重复的情况,假设给定的单词是A和B。
- 对单词A删除一个字符和对单词B增加一个字符是等价的。比如单词A是“abc”,单词B为“bc”时,我们既可以删除单词A的第一个字符a,得到相同的“bc”,也可以在单词B的开头添加一个字符a,得到相同的“abc”。
- 同理,对单词B删除一个字符和对单词A插入一个字符也是等价的。
- 对单词A替换一个字符和对单词B替换一个字符也是等价的。
所以本质上不同的操作只有三种,即
- 在单词A中插入一个字符
- 在单词A中删除一个字符
- 修改单词A中的一个字符
这样我们可以把原问题拆分成若干个子问题,我们假设A="horse",B="ros"。下面来看一下如何具体操作。
- 在单词A中插入一个字符:如果我们知道“horse”到“ro”的编辑距离为a,那么“horse”到“ros”的编辑距离不会超过a+1。因为我们只需要在“horse”的末尾添加一个字符s即可。
- 在单词A中删除一个字符:如果我们知道“hors” 到 “ros”的编辑距离为b,那么“horse”到 “ros”的编辑距离不会超过 b + 1。因为我们只需要删除“horse”的最后一个字符e即可。
- 修改单词A中的一个字符:如果我们知道“hors”到“ro”的编辑距离为c,那么“horse”到 “ros”的编辑距离不会超过 c + 1。因为我们只需要把“horse”的最后一个字符e修改为s即可。
那么从“horse”变成“ros”的最小编辑距离为min(a+1,b+1,c+1)。
所以这道题就可以使用动态规划的方式来求解。我们假设dp[i] [j] 表示word1的前i个字符,变换到word2的前j个字符的最小编辑距离。根据上面的分析,我们可以知道它是由以下三种状态转移的最小值过来的。即
- dp[i] [j] = dp[i] [j-1] +1,即在单词A中增加一个字符
- dp[i] [j] = dp [i-1] [j] + 1,即在单词A中删除一个字符
- dp[i] [j] = dp[i-1] [j-1] +1,即在单词A中替换一个字符
所以动态转移方程为:
若A、B的最后一个字符相同 **dp[i] [j] = min(dp[i] [j-1]+1,dp [i-1] [j]+1,dp[i-1] [j-1]) **。
若A、B的最后一个字符不相同 dp[i] [j] = min(dp[i] [j-1]+1,dp [i-1] [j]+1,dp[i-1] [j-1]+1)。
下面我们来看一下边界情况,一个空串和一个非空串的编辑距离dp[i] [0] = i, dp[0] [j] =j。dp[i] [0] 相当于对word1执行了i次删除操作,dp[0] [j]相当于对word1进行了j次插入操作。
下面我们来看一下代码实现。
class Solution:
def minDistance(self, word1, word2):
#求出单词的长度
n = len(word1)
m = len(word2)
#判断是否是空串
if n==0:
return m
if m==0:
return n
#定义状态转移矩阵
dp = [[0] * (m + 1) for _ in range(n + 1)]
#处理边界条件
for i in range(n + 1):
dp[i][0] = i
for j in range(m + 1):
dp[0][j] = j
#填充状态转移矩阵
for i in range(1, n + 1):
for j in range(1, m + 1):
#上边状态转移过来
up = dp[i - 1][j] + 1
#左边状态转移过来
left = dp[i][j - 1] + 1
#左上的状态
left_up = dp[i - 1][j - 1]
#如果最后一个字符不相同,left_up需要加1
if word1[i - 1] != word2[j - 1]:
left_up += 1
dp[i][j] = min(left, up, left_up)
return dp[n][m]
该算法的时间复杂度和空间复杂度都是O(n*m)。
最后
送大家几本比较不错的算法书籍~
小争哥数据结构与算法
链接:https://pan.baidu.com/s/19Jk_G_-QTnGb3GRyzbENgA
密码:keis
谷歌大佬LeetCode刷题指南
链接:https://pan.baidu.com/s/1vtRIsVltTxmIioqqkeSS5g
密码:r3xg
算法小抄
链接:https://pan.baidu.com/s/1rU_T6GRZ-WmV9QFmnJfCBg
密码:unh5