古生物DNA序列血缘分析
题目要求计算两条DNA序列之间的最小变异次数。DNA序列由四种核苷酸A、C、G、T组成,变异方式包括添加、删除或替换一个核苷酸。变异次数越少,两条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复述一下题目
题目要求计算两条DNA序列之间的最小变异次数。DNA序列由四种核苷酸A、C、G、T组成,变异方式包括添加、删除或替换一个核苷酸。变异次数越少,两条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
需要一点思路提示
要解决这个问题,我们可以使用动态规划(Dynamic Programming, DP)来计算两条DNA序列之间的最小变异次数。动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。
解题思路
-
定义问题:
- 我们需要计算两个字符串
dna1和dna2之间的最小变异次数。 - 变异操作包括插入、删除和替换。
- 我们需要计算两个字符串
-
状态定义:
- 设
dp[i][j]表示dna1的前i个字符和dna2的前j个字符之间的最小变异次数。
- 设
-
状态转移方程:
- 如果
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。
- 如果
-
初始条件:
dp[0][j] = j,表示将空字符串变为dna2的前j个字符需要j次插入操作。dp[i][0] = i,表示将dna1的前i个字符变为空字符串需要i次删除操作。
-
最终结果:
dp[len(dna1)][len(dna2)]即为所求的最小变异次数。
-
- 首先创建了一个二维数组
dp,其行数为dna1序列的长度加 1,列数为dna2序列的长度加 1。这个数组用于保存计算过程中的中间结果。
- 首先创建了一个二维数组
-
- 然后初始化
dp数组的第一行和第一列,第一行表示将dna1序列变为空序列所需的操作次数,第一列表示将空序列变为dna2序列所需的操作次数,这些操作次数都等于对应序列的长度。
- 然后初始化
-
- 接着通过两层循环遍历
dna1和dna2序列的每个位置,根据当前位置的核苷酸是否相同来更新dp数组的值。如果相同,那么当前位置的最小变异次数就等于左上角位置的值(即不进行任何操作);如果不同,则通过取删除、添加和替换操作后的最小值来更新当前位置的值。
- 接着通过两层循环遍历
-
- 最后返回
dp数组右下角的值,这个值就是两条 DNA 序列之间的最小变异次数。
- 最后返回