问题描述
小U是一位古生物学家,正在研究不同物种之间的血缘关系。为了分析两种古生物的血缘远近,她需要比较它们的DNA序列。DNA由四种核苷酸A、C、G、T组成,并且可能通过三种方式发生变异:添加一个核苷酸、删除一个核苷酸或替换一个核苷酸。小U认为两条DNA序列之间的最小变异次数可以反映它们之间的血缘关系:变异次数越少,血缘关系越近。
你的任务是编写一个算法,帮助小U计算两条DNA序列之间所需的最小变异次数。
dna1: 第一条DNA序列。dna2: 第二条DNA序列。
测试样例
样例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
def solution(dna1, dna2): # 获取两个DNA序列的长度 m = len(dna1) n = len(dna2) # 创建动态规划表格 # dp[i][j] 表示将dna1的前i个字符转换为dna2的前j个字符所需的最小操作次数 dp = [[0] * (n + 1) for _ in range(m + 1)] # 初始化第一行和第一列 # 第一行:将空字符串转换为dna2的前j个字符需要j次添加操作 for j in range(n + 1): dp[0][j] = j # 第一列:将dna1的前i个字符转换为空字符串需要i次删除操作 for i in range(m + 1): dp[i][0] = i # 填充动态规划表格 for i in range(1, m + 1): for j in range(1, n + 1): if dna1[i-1] == dna2[j-1]: # 如果当前字符相同,不需要额外操作 dp[i][j] = dp[i-1][j-1] else: # 取三种操作中的最小值: # 1. 替换操作:dp[i-1][j-1] + 1 # 2. 删除操作:dp[i-1][j] + 1 # 3. 添加操作:dp[i][j-1] + 1 dp[i][j] = min(dp[i-1][j-1], dp[i-1][j], dp[i][j-1]) + 1 # 返回最终结果 return dp[m][n]if __name__ == "__main__": # You can add more test cases here print(solution("AGT", "AGCT") == 1) print(solution("", "ACGT") == 4) print(solution("GCTAGCAT", "ACGT") == 5)
这个代码的目标是计算两条DNA序列之间的最小变异次数。变异操作包括添加、删除和替换核苷酸。这个问题可以通过动态规划来解决,因为我们需要找到从一个序列转换到另一个序列的最小操作次数。
数据结构选择
我们选择使用一个二维数组 dp 来存储动态规划的结果。dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最小操作次数。
算法步骤
-
初始化:
- 创建一个
(m+1) x (n+1)的二维数组dp,其中m和n分别是dna1和dna2的长度。 - 初始化第一行和第一列:
dp[0][j]表示将空字符串转换为dna2的前j个字符,需要j次添加操作。dp[i][0]表示将dna1的前i个字符转换为空字符串,需要i次删除操作。
- 创建一个
-
状态转移:
- 对于每个
dp[i][j],如果dna1[i-1] == dna2[j-1],则不需要额外操作,dp[i][j] = dp[i-1][j-1]。 - 否则,取三种操作中的最小值:
- 替换操作:
dp[i-1][j-1] + 1 - 删除操作:
dp[i-1][j] + 1 - 添加操作:
dp[i][j-1] + 1
- 替换操作:
- 对于每个
-
结果:
- 最终结果存储在
dp[m][n]中,表示将dna1转换为dna2所需的最小操作次数
这些是今天11.23的总结了,还在学习ai课程中……