问题重述:
小 R 正在研究 DNA 序列,需要一个函数来确定将受损 DNA 序列(dna1)转换为未受损序列(dna2)所需的最少编辑步骤。可进行的编辑操作包括增加一个碱基、删除一个碱基或替换一个碱基。给出了五个测试样例,分别展示了不同的输入 DNA 序列对及对应的输出最少编辑步骤数。
问题分析:
-
问题本质:这是一个动态规划问题,目标是找到两个 DNA 序列之间的最小编辑距离。
-
编辑操作分析:
- 增加一个碱基:意味着在 dna1 的某个位置插入一个碱基,使其更接近 dna2。
- 删除一个碱基:从 dna1 中删除一个碱基,以匹配 dna2 的长度或序列。
- 替换一个碱基:将 dna1 中的一个碱基替换为另一个碱基,使其与 dna2 中的对应位置碱基相同。
-
动态规划思路:可以考虑使用动态规划的方法来解决这个问题。创建一个二维数组来存储两个序列之间不同长度子序列的最小编辑距离。通过逐步比较两个序列的字符,并根据三种编辑操作的可能性来更新最小编辑距离。最终,数组中的最后一个元素将表示两个完整序列之间的最小编辑距离。
-
测试样例理解:
- 样例 1 中,从 “AGT” 变为 “AGCT” 只需要增加一个碱基 “C”,所以最小编辑步骤为 1。
- 样例 2 中,“AACCGGTT” 变为 “AACCTTGG” 需要进行多次编辑操作,具体过程较为复杂,但通过动态规划可以逐步计算出最小编辑步骤为 4。
- 样例 3 中,“ACGT” 变为 “TGC” 需要进行多个编辑操作,如删除、增加和替换碱基,最小编辑步骤为 3。
- 样例 4 中,“A” 变为 “T” 只需要进行一次替换操作,最小编辑步骤为 1。
- 样例 5 中,“GGGG” 变为 “TTTT” 需要进行四次替换操作,最小编辑步骤为 4。
代码分析:
-
-
参数:
dna1和dna2:两个输入的 DNA 序列字符串。
-
变量初始化:
m, n = len(dna1), len(dna2):分别获取两个 DNA 序列的长度。dp = [[0] * (n + 1) for _ in range(m + 1)]:创建一个二维列表(动态规划表),用于存储两个序列之间不同长度子序列的最小编辑距离。其中m + 1和n + 1是为了考虑空字符串的情况。
-
初始化 dp 表:
- 两个循环分别初始化当一个序列为空字符串时的最小编辑距离。
- 如果要将
dna1转换为空字符串,需要进行i次删除操作,所以dp[i][0] = i。 - 如果要将空字符串转换为
dna2,需要进行j次插入操作,所以dp[0][j] = j。
-
填充 dp 表:
- 两个嵌套的循环遍历两个 DNA 序列的所有可能子序列组合。
- 如果当前位置的两个字符相等,即
dna1[i - 1] == dna2[j - 1],则不需要进行编辑操作,当前最小编辑距离等于上一个子序列的最小编辑距离,即dp[i][j] = dp[i - 1][j - 1]。 - 如果当前位置的两个字符不相等,则需要考虑三种编辑操作(删除、插入、替换),并取其中最小的编辑距离。
dp[i - 1][j] + 1表示删除操作,即从dna1中删除当前字符。dp[i][j - 1] + 1表示插入操作,即在dna1中插入当前dna2的字符。dp[i - 1][j - 1] + 1表示替换操作,即将dna1中的当前字符替换为dna2中的当前字符。
-
返回值:
dp[m][n]返回两个完整 DNA 序列之间的最小编辑距离。
-
-
if __name__ == "__main__":部分:- 这里是用于测试的代码部分。
- 调用
solution函数并传入两个 DNA 序列,然后将函数返回值与预期的最小编辑距离进行比较,并打印比较结果。