【题目】
给定两个字符str1和str2,再给定三个整数ic,dc,rc,分别代表插入,删除和替换一个字符的代价,返回将str1编辑成str2的最小代价。
【举例】
str1 = “abc”,str2 = “adc”,ic = 5,dc = 3,rc = 100。
从str1编辑到str2,先删除’b’,然后插入’d’是代价最小的,所以返回8。
【基本思路】
如果str1的长度为N,str2的长度为M,生成(N+1)×(M+1)的矩阵dp,为什么N+1,M+1,因为我们需要在字符串的开头添加一个空字符的特殊情况,dp[i][j]的值代表str1[0…i-1]编辑成str2[0…j-1]的最小代价。dp的计算如下:
矩阵的第一行表示空字符编辑成str2[0…j-1]所需要的最小代价,当然只需要插入操作即可,所以dp[0][j] = ic * j。
矩阵的第一列表示str1[0…i-1]编辑成空字符所需要的最小代价,当然只需要删除操作即可,所以dp[i][0] = dc * i。
矩阵的其他位置来自以下的三种情况:dp[i-1][j]+dc,dp[i][j-1]+ic,(dp[i-1][j-1] or dp[i-1][j-1]+rc)。
1)dp[i-1][j] + dc,表示先删除str1[i-1],然后将str1[0…i-2]编辑成str2[0…j-1]2)dp[i][j-1] + ic,表示将str1[i-1]编辑成str2[0…j-2],然后再插入str2[j-1]
3)dp[i-1][j-1] or dp[i-1][j-1]+rc,表示如果str1[i-1] != str2[j-1],则先将str1[0…i-2]编辑成str2[0…j-2]再将str1[i-1]替换成str2[j-1],如果str1[i-1] == str2[j-1],则将str1[0…i-2]编辑成str2[0…j-2]后就不需要进行替换了。
下面是用python3.5实现的代码
#最小编辑代价
#经典动态规划方法。时间复杂度O(M*N),空间复杂度O(M*N)
def minCoin(str1, str2, ic, dc, rc):
if str1 == None or str2 == None:
return 0
row = len(str1) + 1
col = len(str2) + 1
dp = [[0 for i in range(col)] for j in range(row)]
for i in range(row):
dp[i][0] = i * dc
for j in range(col):
dp[0][j] = j * ic
for i in range(1, row):
for j in range(1, col):
if str1[i-1] == str2[j-1]:
dp[i][j] = dp[i-1][j-1]
else:
dp[i][j] = dp[i-1][j-1] + rc
dp[i][j] = min(dp[i][j], dp[i][j-1] + ic)
dp[i][j] = min(dp[i][j], dp[i-1][j] + dc)
return dp[-1][-1]
#动态规划+空间压缩。时间复杂度O(M*N),空间复杂度O(min{M,N})
def minCoin2(str1, str2, ic, dc, rc):
if str1 == None or str2 == None:
return 0
longs = str1 if len(str1) >= len(str2) else str2
shorts = str1 if len(str1) < len(str2) else str2
if longs == str2:
ic, dc = dc, ic
dp = [0 for i in range(len(shorts)+1)]
for i in range(len(dp)):
dp[i] = ic * i
for i in range(1, len(longs)+1):
leftUp = dp[0]
dp[0] = i * dc
for j in range(1, len(shorts)+1):
up = dp[j]
if longs[i-1] == shorts[j-1]:
dp[j] = leftUp
else:
dp[j] = leftUp + rc
dp[j] = min(dp[j], up+dc)
dp[j] = min(dp[j], dp[j-1]+ic)
leftUp = up
return dp[-1]