题目内容
小R正在研究DNA序列,他需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
题目分析
问题理解
这道题实际上是一道线性DP的题目,可以将其描述为:
给定两个字符串A和B,现在要将A经过若干操作变为B,可进行的操作有:
- 删除——将字符串A中的某个字符删除
- 插入——在字符串A的某个位置插入某个字符
- 替换——将字符串A中的某个字符替换为另一个字符
现在请你求出,将A变为B至少需要进行多少次操作。
定义状态
我们使用一个二维数组 dp,其中 dp[i][j] 表示将 dna1 的前 i 个字符转换成 dna2 的前 j 个字符所需的最少编辑步骤。
初始化
首先,我们需要初始化 dp 数组。dp[i][0] 表示将 dna1 的前 i 个字符转换成空字符串所需的编辑步骤数,显然需要 i 次删除操作。同理,dp[0][j] 表示将空字符串转换成 dna2 的前 j 个字符所需的编辑步骤数,显然需要 j 次插入操作。
状态转移
接下来,我们填充 dp 数组。对于每个 dp[i][j],我们有以下三种情况:
-
如果
dna1[i-1] == dna2[j-1]:- 这意味着
dna1的第i-1个字符和dna2的第j-1个字符相同,不需要进行任何编辑操作。 - 因此,
dp[i][j] = dp[i-1][j-1]。
- 这意味着
-
如果
dna1[i-1] != dna2[j-1]:-
这意味着我们需要进行编辑操作。我们有三种选择:
- 插入操作:在
dna1的第i个位置插入dna2[j-1],这样dna1的前i个字符就变成了dna2的前j-1个字符。因此,dp[i][j] = dp[i][j-1] + 1。 - 删除操作:删除
dna1的第i-1个字符,这样dna1的前i-1个字符就变成了dna2的前j个字符。因此,dp[i][j] = dp[i-1][j] + 1。 - 替换操作:将
dna1的第i-1个字符替换为dna2的第j-1个字符,这样dna1的前i-1个字符就变成了dna2的前j-1个字符。因此,dp[i][j] = dp[i-1][j-1] + 1。
- 插入操作:在
-
我们选择这三种操作中的最小值:
dp[i][j] = min(dp[i][j-1] + 1, dp[i-1][j] + 1, dp[i-1][j-1] + 1)。
-
最终结果
dp[len(dna1)][len(dna2)] 即为将 dna1 转换成 dna2 所需的最少编辑步骤。
具体例子
dna1 = "AGT", dna2 = "AGCT"
-
初始化:
-
dp[0][j]:将空字符串转换成dna2的前j个字符。dp[0][0] = 0dp[0][1] = 1(插入 'A')dp[0][2] = 2(插入 'A' 和 'G')dp[0][3] = 3(插入 'A'、'G' 和 'C')dp[0][4] = 4(插入 'A'、'G'、'C' 和 'T')
-
dp[i][0]:将dna1的前i个字符转换成空字符串。dp[1][0] = 1(删除 'A')dp[2][0] = 2(删除 'A' 和 'G')dp[3][0] = 3(删除 'A'、'G' 和 'T')
-
-
状态转移:
| A | G | C | T | ||
|---|---|---|---|---|---|
| 0 | 1 | 2 | 3 | 4 | |
| A | 1 | 0 | 1 | 2 | 3 |
| G | 2 | 1 | 0 | 1 | 2 |
| T | 3 | 2 | 1 | 1 | 1 |
- 最终结果:
dp[3][4] = 1,即将 dna1 = "AGT" 转换成 dna2 = "AGCT" 所需的最少编辑步骤为 1。
参考代码
def solution(dna1, dna2):
m, n = len(dna1), len(dna2)
dp = [[0] * (n + 1) for _ in range(m + 1)]
# 初始化 dp 数组
for i in range(m + 1):
dp[i][0] = i
for j in range(n + 1):
dp[0][j] = j
# 动态规划
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 - 1] + 1, # 替换
dp[i - 1][j] + 1, # 删除
dp[i][j - 1] + 1) # 插入
return dp[m][n]
总结
- 时间复杂度:
O(m * n),其中m和n分别是dna1和dna2的长度。 - 空间复杂度:
O(m * n),用于存储dp数组。
通过动态规划,我们可以有效地计算出将一个DNA序列转换成另一个DNA序列所需的最少编辑步骤。这个方法不仅适用于DNA序列,还可以应用于其他字符串编辑距离问题。