AI刷题实践:DNA序列编辑距离 | 豆包MarsCode AI刷题

57 阅读3分钟

问题描述

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

思路

这种有许多步骤组成的问题,可以化成许多子问题解决,可以立刻联想到动态规划,动态规划的核心思想是将问题分解为子问题,并存储子问题的解以避免重复计算。

  1. 定义状态

    • 我们使用一个二维数组 dp,其中 dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最少编辑步骤。
  2. 初始化

    • 当 dna2 为空时,将 dna1 转换为空序列需要删除 dna1 的所有字符,因此 dp[i][0] = i
    • 当 dna1 为空时,将空序列转换为 dna2 需要添加 dna2 的所有字符,因此 dp[0][j] = j
  3. 状态转移

  • 情况1:字符匹配

    • 如果 dna1[i-1] == dna2[j-1],则不需要进行任何编辑操作,dp[i][j] = dp[i-1][j-1]
    • 这是因为当前字符已经匹配,不需要额外的编辑步骤。
  • 情况2:字符不匹配

    • 如果 dna1[i-1] != dna2[j-1],则需要考虑三种编辑操作:

      • 插入:在 dna1 中插入一个字符使其与 dna2 匹配,dp[i][j] = dp[i][j-1] + 1

        • 这意味着我们在 dna1 的末尾插入一个字符,使得 dna1 的前 i 个字符与 dna2 的前 j-1 个字符匹配,然后再加上插入操作的代价 1
      • 删除:删除 dna1 中的一个字符,dp[i][j] = dp[i-1][j] + 1

        • 这意味着我们删除 dna1 的第 i 个字符,使得 dna1 的前 i-1 个字符与 dna2 的前 j 个字符匹配,然后再加上删除操作的代价 1
      • 替换:将 dna1 中的一个字符替换为 dna2 中的字符,dp[i][j] = dp[i-1][j-1] + 1

        • 这意味着我们将 dna1 的第 i 个字符替换为 dna2 的第 j 个字符,使得 dna1 的前 i-1 个字符与 dna2 的前 j-1 个字符匹配,然后再加上替换操作的代价 1

在字符不匹配的情况下,我们需要选择上述三种操作中代价最小的那个,即

dp[i][j] = Math.min(dp[i-1][j], Math.min(dp[i][j-1], dp[i-1][j-1])) + 1;

  1. 结果

    • 最终结果存储在 dp[len1][len2] 中,其中 len1 和 len2 分别是 dna1 和 dna2 的长度。

这个方法的时间复杂度为 O(n*m),其中 n 和 m 分别是两个序列的长度。

写在最后:

其实这道题就是最长公共子序列问题的变式,最长公共子序列,最长递增子序列,最长回文子序列等都是类似的思路,定义dp[i][j]为text1的前i个字符和ext2的前j个字符的最长公共子序列的长度。