题目
题目链接
给出2个只含小写字母的字符串str1,str2
,求将str1
编辑为str2
的最少代价
可以进行的编辑操作有如下3种,代价均为1:
- 修改一个字符
- 删除一个字符
- 增加一个字符
动态规划
如下图(以将“nowcoder”
转变为“new”
为例),设置dp数组,dp[i][j]
表示str1[:i]
转变为str2[:j]
的代价;行对应str1
,列对应str2
(第一行第一列表示空串);初始时全为0
首先初始化第一行为:dp[0][i]=dp[0][i-1],表示:从空串开始转化成另一个字符串的代价,是每次增加1个字符
再初始化第一列为:dp[i][0]=dp[i-1][0]+1,表示:从str1[:i]转化为空串所需要的代价,是每次删除1个字符
要将str1[:i]
转变为str2[:j]
,可能有以下情况:
- 若
str1[i-1] == str2[j-1]
,本次不用编辑,则当前状态的代价dp[i][j]
可以直接取dp[i-1][j-1]
- 若
str1[i-1] != str2[j-1]
,本次需要编辑,一定会使代价+1;
因为有3种
编辑方法,当前代价可能由3种
情况转变而来:
① 修改当前字符,代价为dst[i - 1][j - 1]+1
例如当前状态为
no→ne
,则取上一个状态为n→n
,代价为dst[i - 1][j - 1]
,本次代价就为dst[i - 1][j - 1]+1
② 删除1个字符,代价为dst[i - 1][j]+1
例如当前状态为
no→n
,则取上一个状态为n→n
,代价为dst[i-1][j]+1
,本次代价就为dst[i-1][j]+1
③ 新增1个字符,代价为dst[i][j - 1]+1
例如当前状态为
n→ne
,则取上一个状态为n→n
,代价为dst[i][j - 1]+1
,本次代价就为dst[i][j -1]+1
最后得到完整的dp数组如下图,最后一个元素即为总体的最小代价
代码
class Solution:
# 将str1转换为str2
def editDistance(self, str1, str2):
# dst[i][j]表示把str1[:i]转化成str[:j]的代价,ij=0处表示的是空串
dst = [[0] * (len(str2) + 1) for _ in range(len(str1) + 1)]
# 初始化第一行第一列
for i in range(1, len(str2) + 1):
dst[0][i] = dst[0][i - 1] + 1
for i in range(1, len(str1) + 1):
dst[i][0] = dst[i - 1][0] + 1
for i in range(1, len(str1) + 1):
for j in range(1, len(str2) + 1):
if str1[i - 1] != str2[j - 1]:
dst[i][j] = min(dst[i - 1][j] , dst[i][j - 1] , dst[i - 1][j - 1])+1
else:
dst[i][j]=dst[i-1][j-1]
return dst[-1][-1]