1. 理解问题
这个问题可以通过动态规划中的编辑距离算法(Levenshtein 距离)来解决。编辑距离是指将一个字符串转换为另一个字符串所需的最少单字符编辑操作次数,这里的单字符编辑操作就是题目中提到的增加一个碱基、删除一个碱基或替换一个碱基。
2. 算法思路
我们可以创建一个二维数组来保存中间结果,其中数组的行对应 dna1
中的字符位置,列对应 dna2
中的字符位置。通过填充这个二维数组,我们可以逐步计算出将 dna1
的前 i
个字符转换为 dna2
的前 j
个字符所需的最少编辑步骤。
3. 代码实现
def min_edit_distance(dna1, dna2):
m = len(dna1)
n = 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] = min(
dp[i - 1][j] + 1, # 删除操作
dp[i][j - 1] + 1, # 插入操作
dp[i - 1][j - 1] + 1 # 替换操作
)
return dp[m][n]
在上述代码中:
-
首先,我们获取了
dna1
和dna2
的长度m
和n
。 -
然后,创建了一个二维数组
dp
,并初始化了第一行和第一列。第一行表示将空字符串转换为dna2
的前j
个字符所需的编辑步骤,即插入j
个字符,所以dp[0][j] = j
;第一列表示将dna1
的前i
个字符转换为空字符串所需的编辑步骤,即删除i
个字符,所以dp[i][0] = i
。 -
接下来,通过两层嵌套的循环来填充二维数组的其余部分。对于
dp[i][j]
,如果dna1
的第i - 1
个字符和dna2
的第j - 1
个字符相同,那么不需要进行任何编辑操作,dp[i][j]
的值就等于dp[i - 1][j - 1]
。如果不相同,我们就需要考虑三种操作:删除dna1
的第i - 1
个字符(对应dp[i - 1][j] + 1
)、插入一个字符使其与dna2
的第j - 1
个字符相同(对应dp[i][j - 1] + 1
)、替换dna1
的第i - 1
个字符使其与dna2
的第j - 1
个字符相同(对应dp[i - 1][j - 1] + 1
),然后取这三种情况中的最小值作为dp[i][j]
的值。 -
最后,返回
dp[m][n]
,它就是将整个dna1
序列转换为整个dna2
序列所需的最少编辑步骤。
你可以使用以下方式调用这个函数:
dna1 = "ACGT"
dna2 = "AGCT"
print(min_edit_distance(dna1, dna2))
在上述示例中,我们定义了两个 DNA 序列 dna1
和 dna2
,然后调用 min_edit_distance
函数来计算将 dna1
转换为 dna2
所需的最少编辑步骤,并将结果打印出来。