每日算法:DNA序列编辑距离

62 阅读3分钟

题目本体

题目名称: 最小编辑步骤

题目描述: 小R需要一个函数来计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。

输入格式:

  • 第一个字符串为受损DNA序列 dna1
  • 第二个字符串为未受损DNA序列 dna2

输出格式:

  • 输出一个整数,代表最少编辑步骤。

示例:

  • 输入:dna1 = "AGT"dna2 = "AGCT"
  • 输出:1

限制条件:

  • 无额外限制。

题目思路

1、题目理解与算法选择

该问题属于经典的编辑距离问题,其核心在于找到从一个序列转换到另一个序列的最优操作路径,使得操作次数最少。动态规划是解决此类问题的有效方法,原因在于它能够巧妙地处理具有重叠子问题和最优子结构特性的情况。所谓重叠子问题,是指在计算过程中,会多次遇到相同的子序列转换问题;而最优子结构特性则表明,整个序列的最优编辑距离可以通过其子序列的最优编辑距离逐步构建得到。

2、关键点分析与状态转移方程

在动态规划的实现过程中,状态转移是关键环节。我们定义一个二维数组 dp,其中 dp [i][j] 表示将 dna1 的前 i 个碱基转换成 dna2 的前 j 个碱基所需的最少编辑步骤。当考虑当前两个碱基 dna1 [i - 1] 和 dna2 [j - 1] 时,如果它们相同,那么 dp [i][j] 就等于 dp [i - 1][j - 1],因为不需要进行任何编辑操作。然而,当它们不同时,我们有三种选择:插入、删除或替换。插入操作意味着在 dna1 的前 i 个碱基基础上插入一个碱基以匹配 dna2 的第 j 个碱基,此时 dp [i][j] = dp [i][j - 1] + 1;删除操作表示删除 dna1 的第 i 个碱基,即 dp [i][j] = dp [i - 1][j] + 1;替换操作则是将 dna1 的第 i 个碱基替换为 dna2 的第 j 个碱基,所以 dp [i][j] = dp [i - 1][j - 1] + 1。综合这三种情况,我们取最小值,即 dp [i][j] = min (dp [i - 1][j], dp [i][j - 1], dp [i - 1][j - 1]) + 1。

代码详解

python
def solution(dna1, dna2):
    m, n = len(dna1), 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], dp[i][j-1], dp[i-1][j-1]) + 1
    return dp[m][n]
  • 代码解释:

    • 初始化一个二维数组 dp,其中 dp[i][j] 表示将 dna1 的前 i 个碱基转换成 dna2 的前 j 个碱基所需的最少编辑步骤。
    • 填充 dp 数组的第一行和第一列,表示从空字符串到任意序列的编辑步骤。
    • 使用双层循环遍历 dp 数组,根据当前两个碱基是否相同来决定状态转移。

总结分析

  • 算法复杂度:

    • 时间复杂度:O(m * n),其中 m 和 n 分别是两个DNA序列的长度。
    • 空间复杂度:O(m * n),需要一个大小为 (m+1) x (n+1) 的数组来存储动态规划的状态。
  • 算法优缺点:

    • 优点:能够找到最优解,适用于这个问题。
    • 缺点:对于大数据量,时间复杂度较高,可能需要优化。