DNA序列编辑距离题解| 豆包MarsCode AI 刷题

120 阅读2分钟

这里简单讲解一下 [DNA序列编辑距离](DNA序列编辑距离 - MarsCode) 这道题目,我在写的时候还是遇到了一点小坑的。

题目大意:

小R正在研究DNA序列,他需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。

测试样例(这里直接给代码中的样例了,不太清楚题目描述里的样例有啥用):

样例1:

输入:dna1 = "AGCTTAGC",dna2 = "AGCTAGCT"
输出:2

样例解释:

删除dna1中的第4或5个字符T,删除dna2中的最后一个字符T

样例2:

输入:dna1 = "AGCCGAGC",dna2 = "GCTAGCT"
输出:4

样例解释:

删除dna1中的第1和第4个字符,删除dna2中的最后一个字符,将dna1中的第5个字符G替换为T

求解思路

先讲一下我遇到的坑。

第一眼看到题感觉是最长公共子序列的变形,求解dna1和dna2的最长公共子序列,然后用dna1和dna2的长度和减去2倍最长公共子序列长度即为答案。但是大意了,没有考虑替换这一情况,从上面的第二个样例就能看出。

于是只能转换思路,直接求解所需要的最小替换次数。

依然没有跳出最长公共子序列的框架(不了解最长公共子序列的可以先去LeetCode找题先做一下),只是从逆向求解变成正向求解。

dp数组含义:dp[i][j]为使dna1中前i个与dna2中前j个元素组成的字串相等的最小操作数

  1. 初始化边界条件

    • dp[i][0] = i 和 dp[0][j] = j 表示将一个空字符串转换成另一个字符串需要 i 或 j 次操作。
  2. 状态转移

    • 如果 dna1[i-1] == dna2[j-1],表示不需要额外操作。dp[i][j] = dp[i-1][j-1] 
    • 表示选择删除、插入或替换操作中的最小值,并加上一次操作,dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1 

AC代码如下:

def solution(dna1, dna2):
    print(dna1, dna2)
    # 获取dna1和dna2的长度
    len1, len2 = len(dna1), len(dna2)
    
    # 初始化动态规划数组
    dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
    
    # 初始化边界条件
    for i in range(1, len1 + 1):
        dp[i][0] = i
    for j in range(1, len2 + 1):
        dp[0][j] = j
    
    # 遍历dp数组求解
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 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], dp[i][j-1], dp[i-1][j-1]) + 1
    
    # 返回编辑距离
    return dp[len1][len2]