青训营 X 豆包MarsCode AI 刷题

51 阅读3分钟

古生物DNA序列血缘分析

题目要求计算两条DNA序列之间的最小变异次数。DNA序列由四种核苷酸A、C、G、T组成,变异方式包括添加、删除或替换一个核苷酸。变异次数越少,两条DNA序列之间的血缘关系越近。

具体任务是编写一个算法,输入两条DNA序列dna1dna2,输出它们之间的最小变异次数。

测试样例

样例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 复述一下题目

题目要求计算两条DNA序列之间的最小变异次数。DNA序列由四种核苷酸A、C、G、T组成,变异方式包括添加、删除或替换一个核苷酸。变异次数越少,两条DNA序列之间的血缘关系越近。

具体任务是编写一个算法,输入两条DNA序列dna1dna2,输出它们之间的最小变异次数。

测试样例

样例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

需要一点思路提示

要解决这个问题,我们可以使用动态规划(Dynamic Programming, DP)来计算两条DNA序列之间的最小变异次数。动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。

解题思路

  1. 定义问题

    • 我们需要计算两个字符串 dna1dna2 之间的最小变异次数。
    • 变异操作包括插入、删除和替换。
  2. 状态定义

    • dp[i][j] 表示 dna1 的前 i 个字符和 dna2 的前 j 个字符之间的最小变异次数。
  3. 状态转移方程

    • 如果 dna1[i-1] == dna2[j-1],则 dp[i][j] = dp[i-1][j-1],因为当前字符相同,不需要变异。
    • 否则,dp[i][j] 可以通过以下三种操作之一得到:
      • 插入:dp[i][j] = dp[i][j-1] + 1
      • 删除:dp[i][j] = dp[i-1][j] + 1
      • 替换:dp[i][j] = dp[i-1][j-1] + 1
    • 因此,dp[i][j] = min(dp[i][j-1], dp[i-1][j], dp[i-1][j-1]) + 1
  4. 初始条件

    • dp[0][j] = j,表示将空字符串变为 dna2 的前 j 个字符需要 j 次插入操作。
    • dp[i][0] = i,表示将 dna1 的前 i 个字符变为空字符串需要 i 次删除操作。
  5. 最终结果

    • dp[len(dna1)][len(dna2)] 即为所求的最小变异次数。

    1. 首先创建了一个二维数组 dp,其行数为 dna1 序列的长度加 1,列数为 dna2 序列的长度加 1。这个数组用于保存计算过程中的中间结果。
    1. 然后初始化 dp 数组的第一行和第一列,第一行表示将 dna1 序列变为空序列所需的操作次数,第一列表示将空序列变为 dna2 序列所需的操作次数,这些操作次数都等于对应序列的长度。
    1. 接着通过两层循环遍历 dna1 和 dna2 序列的每个位置,根据当前位置的核苷酸是否相同来更新 dp 数组的值。如果相同,那么当前位置的最小变异次数就等于左上角位置的值(即不进行任何操作);如果不同,则通过取删除、添加和替换操作后的最小值来更新当前位置的值。
    1. 最后返回 dp 数组右下角的值,这个值就是两条 DNA 序列之间的最小变异次数。