青训营X豆包MarsCode技术训练营|豆包MarsCode AI刷题

41 阅读2分钟

对“小U是一位古生物学家,正在研究不同物种之间的血缘关系。为了分析两种古生物的血缘远近,她需要比较它们的DNA序列。DNA由四种核苷酸A、C、G、T组成,并且可能通过三种方式发生变异:添加一个核苷酸、删除一个核苷酸或替换一个核苷酸。小U认为两条DNA序列之间的最小变异次数可以反映它们之间的血缘关系:变异次数越少,血缘关系越近。

你的任务是编写一个算法,帮助小U计算两条DNA序列之间所需的最小变异次数。dna1: 第一条DNA序列。dna2: 第二条DNA序列。”的解析: 代码的实现: def solution(dna1, dna2): m, n = len(dna1), len(dna2) # 创建一个 (m+1) x (n+1) 的二维数组 dp dp = [[0] * (n + 1) for _ in range(m + 1)]

# 初始化边界条件
for i in range(m + 1):
    dp[i][0] = i
for j in range(n + 1):
    dp[0][j] = j

# 填充 dp 数组
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:
            dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1

return dp[m][n]

if name == "main": # 测试样例 print(solution("AGT", "AGCT") == 1) print(solution("AACCGGTT", "AACCTTGG") == 4) print(solution("ACGT", "TGC") == 3) print(solution("A", "T") == 1) print(solution("GGGG", "TTTT") == 4) 为了帮助小U计算两条DNA序列之间的最小变异次数,我们可以使用动态规划的方法来解决这个问题。这个问题的本质是计算两个字符串之间的编辑距离(Edit Distance),也称为莱文斯坦距离(Levenshtein Distance)。 1.定义状态:设 'dp[i][j]'表示 'dna1' 的前 'i' 个字符和 'dna2' 的前 'j' 个字符之间的最小变异次数。2.状态转移方程:如果 'dna1[i-1] == dna2[j-1]',则'dp[i][j] = dp[i-1][j-1]',因为当前字符相同,不需要变异。否则,'dp[i][j]' 可以通过以下三种操作之一得到:插入:'dp[i][j-1] + 1',即在 'dna' 中插入一个字符使其与 'dna2' 的第 'j'个字符匹配。删除:'dp[i-1][j] + 1',即删除'dna1'中的第'i' 个字符。替换:'dp[i-1][j-1] + 1',即将 'dna1' 中的第 'i' 个字符替换为 'dna2' 中的第 'j' 个字符。 因此,'dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1'。3. 初始条件:'dp[0][j] = j',表示 'dna1'为空时,需要 'j'次插入操作。'dp[i][0] = i',表示'dna2'为空时,需要 'i'次删除操作。4.最终结果:dp[len(dna1)][len(dna2)]' 即为所求的最小变异次数。 这个算法的时间复杂度为 'O(m * n)',其中 'm' 和 'n' 分别是'dna1' 和 'dna2' 的长度。空间复杂度也是'O(m * n)',因为我们需要存储整个 'dp' 数组。