问题描述
小R正在研究DNA序列,他需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
测试样例
样例1:
输入:dna1 = "AGT",dna2 = "AGCT" 输出:1
样例2:
输入:dna1 = "AACCGGTT",dna2 = "AACCTTGG" 输出:4
样例3:
输入:dna1 = "ACGT",dna2 = "TGC" 输出:3
样例4:
输入:dna1 = "A",dna2 = "T" 输出:1
样例5:
输入:dna1 = "GGGG",dna2 = "TTTT" 输出:4
解题思路
这道题目属于经典的动态规划算法题(“编辑距离”)。
首先来解释下“编辑距离”:
所谓“编辑距离”就是给定我们两个字符串 s1 和 s2,只能用三种操作(增加1个字符、删除一个字符或替换一个字符),让我们把 s1 变成 s2,其最少的操作数。
我们定义二维数组dp ,dp[i][j]表示字符串s1[1...i]和s2[1...j]之间的编辑距离(这里我默认索引从1开始)
那么我们现在就可以先来分析两种情况:
s1[i] == s2[j]
if s1[i] == s2[j]: # 啥都不做
return dp[i-1][j-1]
# 解释: # 本来就相等,不需要任何操作
# s1[0..i] 和 s2[0..j] 的最小编辑距离等于
# s1[0..i-1] 和 s2[0..j-1] 的最小编辑距离
# 也就是说 dp(i, j) 等于 dp(i-1, j-1)
2.s1[i] != s2[j]
那么就要考虑一下三种情况:
dp[i - 1][j - 1]+1 #replace
dp[i][ j - 1]+1 #insert
dp[i - 1][ j]+1 #delete
上面哪个小,dp[i][j]就取谁。
最后返回dp[m][n]即可(m,n分别是s1,s2的长度)
完整代码
def solution(dna1, dna2):
m, n = len(dna1), len(dna2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
for i in range(m + 1):
dp[i][0] = i
for j in range(n + 1):
dp[0][j] = j
for i in range(1, m + 1):
for j in range(1, n + 1):
if dna1[i - 1] == dna2[j - 1]:
dp[i][j] = dp[i - 1][j - 1]
else:
dp[i][j] = 1 + min(dp[i - 1][j], # Deletion
dp[i][j - 1], # Insertion
dp[i - 1][j - 1] # Substitution
)
return dp[m][n]
如有疏漏,欢迎指正!