豆包刷题:DNA序列编辑距离

123 阅读3分钟

问题描述

小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

思路

  1. 定义状态

    • 设 dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最少操作次数。
  2. 状态转移

    • 插入操作:如果我们将 dna1[0..i] 转换为 dna2[0..j-1],然后插入 dna2[j-1],那么 dp[i][j] = dp[i][j-1] + 1
    • 删除操作:如果我们将 dna1[0..i-1] 转换为 dna2[0..j],然后删除 dna1[i-1],那么 dp[i][j] = dp[i-1][j] + 1
    • 替换操作:如果 dna1[i-1] 和 dna2[j-1] 相同,不需要操作,所以 dp[i][j] = dp[i-1][j-1];如果不同,则需要进行替换操作,dp[i][j] = dp[i-1][j-1] + 1
  3. 初始化

    • dp[i][0] = i:将 dna1 的前 i 个字符转换为空串需要 i 次删除操作。
    • dp[0][j] = j:将空串转换为 dna2 的前 j 个字符需要 j 次插入操作。
  4. 最终结果

    • dp[len(dna1)][len(dna2)] 即为将 dna1 转换为 dna2 的最少操作次数。

时间复杂度与空间复杂度分析

  1. 时间复杂度O(m * n),其中 mdna1 的长度,ndna2 的长度。我们需要填充一个 m x n 的动态规划表,对于每一个位置,我们只做常数时间的操作。因此时间复杂度为 O(m * n)
  2. 空间复杂度O(m * n),用于存储 DP 表。我们为每一对 ij 计算最小编辑距离,需要一个 m x n 的二维数组来存储中间结果。如果希望节省空间,可以使用滚动数组来优化,将空间复杂度降至 O(min(m, n))

优化空间复杂度

对于较长的序列,如果只是关注最终结果而不需要保留整个 DP 表的中间状态,可以通过滚动数组来减少空间开销。

在每一步,只需要保存当前行和上一行的数据。因此可以将空间复杂度优化为 O(min(m, n)),从而节省内存。

总结

动态规划方法是解决编辑距离问题的经典方式,通过递归分解原问题为子问题并存储中间结果,避免重复计算,达到了高效的时间复杂度 O(m * n)。空间复杂度方面,初步实现需要 O(m * n) 空间,但可以通过优化将空间复杂度降低。