DNA序列编辑距离题目解析 | 豆包MarsCode AI刷题

1 阅读3分钟

1. 理解问题

这个问题可以通过动态规划中的编辑距离算法(Levenshtein 距离)来解决。编辑距离是指将一个字符串转换为另一个字符串所需的最少单字符编辑操作次数,这里的单字符编辑操作就是题目中提到的增加一个碱基、删除一个碱基或替换一个碱基。

2. 算法思路

我们可以创建一个二维数组来保存中间结果,其中数组的行对应 dna1 中的字符位置,列对应 dna2 中的字符位置。通过填充这个二维数组,我们可以逐步计算出将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最少编辑步骤。

3. 代码实现

def min_edit_distance(dna1, dna2):
    m = len(dna1)
    n = len(dna2)

    # 创建二维数组并初始化第一行和第一列
    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

    # 填充二维数组的其余部分
    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,  # 删除操作
                    dp[i][j - 1] + 1,  # 插入操作
                    dp[i - 1][j - 1] + 1  # 替换操作
                )

    return dp[m][n]

在上述代码中:

  • 首先,我们获取了 dna1 和 dna2 的长度 m 和 n

  • 然后,创建了一个二维数组 dp,并初始化了第一行和第一列。第一行表示将空字符串转换为 dna2 的前 j 个字符所需的编辑步骤,即插入 j 个字符,所以 dp[0][j] = j;第一列表示将 dna1 的前 i 个字符转换为空字符串所需的编辑步骤,即删除 i 个字符,所以 dp[i][0] = i

  • 接下来,通过两层嵌套的循环来填充二维数组的其余部分。对于 dp[i][j],如果 dna1 的第 i - 1 个字符和 dna2 的第 j - 1 个字符相同,那么不需要进行任何编辑操作,dp[i][j] 的值就等于 dp[i - 1][j - 1]。如果不相同,我们就需要考虑三种操作:删除 dna1 的第 i - 1 个字符(对应 dp[i - 1][j] + 1)、插入一个字符使其与 dna2 的第 j - 1 个字符相同(对应 dp[i][j - 1] + 1)、替换 dna1 的第 i - 1 个字符使其与 dna2 的第 j - 1 个字符相同(对应 dp[i - 1][j - 1] + 1),然后取这三种情况中的最小值作为 dp[i][j] 的值。

  • 最后,返回 dp[m][n],它就是将整个 dna1 序列转换为整个 dna2 序列所需的最少编辑步骤。

你可以使用以下方式调用这个函数:

dna1 = "ACGT"
dna2 = "AGCT"
print(min_edit_distance(dna1, dna2))

在上述示例中,我们定义了两个 DNA 序列 dna1 和 dna2,然后调用 min_edit_distance 函数来计算将 dna1 转换为 dna2 所需的最少编辑步骤,并将结果打印出来。