青训营X豆包MarsCode 技术训练营刷题技巧(动态规划专题篇三) | 豆包MarsCode AI 刷题

75 阅读3分钟

image.png 第二轮66刷题任务over!放图待补充

DNA序列编辑问题

问题描述

image.png

问题分析

这是一道经典的 编辑距离问题,常用于比较字符串的相似性,DNA序列比对是其中的典型应用。

这个问题的核心是计算两个字符串之间的最小变换成本,DNA序列问题本质是一个字符串编辑问题,其实质是找到 dna1dna2最大相似子序列,通过最小化编辑操作来实现转换:

  • 插入操作: 模拟 DNA 链中插入新的碱基对;
  • 删除操作: 模拟 DNA 链中删除已有碱基对;
  • 替换操作: 模拟突变,即将一个碱基对变成另一个碱基对

动态规划状态分析:

  • 状态定义:

    • dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最小操作数。
  • 状态转移:

    • 假设当前考虑的是 dna1 的第 i 个字符和 dna2 的第 j 个字符:

      • 如果两字符相同,即 dna1[i-1] == dna2[j-1],不需要额外操作: dp[i][j]=dp[i−1][j−1]dp[i][j] = dp[i-1][j-1]dp[i][j]=dp[i−1][j−1]

      • 如果两字符不同,需要考虑三种可能的操作:

        1. 删除字符 dna1[i-1](相当于从 i-1 位置转移到 i 位置):dp[i-1][j] + 1
        2. 插入字符 dna2[j-1](相当于从 j-1 位置转移到 j 位置):dp[i][j-1] + 1
        3. 替换字符 dna1[i-1]dna2[j-1](相当于直接替换):dp[i-1][j-1] + 1
      • 状态转移方程: dp[i][j]=min⁡(dp[i−1][j]+1,dp[i][j−1]+1,dp[i−1][j−1]+1)dp[i][j] = \min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + 1)dp[i][j]=min(dp[i−1][j]+1,dp[i][j−1]+1,dp[i−1][j−1]+1)

  • 初始化:

    • 如果 dna1 是空串(长度为 0),需要将 dna2 的所有字符插入: dp[0][j]=jdp[0][j] = jdp[0][j]=j
    • 如果 dna2 是空串(长度为 0),需要删除 dna1 的所有字符: dp[i][0]=idp[i][0] = idp[i][0]=i
  • 结果:

    • 我们需要的最小编辑距离就是 dp[m][n],其中 mn 分别是 dna1dna2 的长度。

Python代码

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

    # 创建一个(m+1) x (n+1)的二维列表来保存编辑距离
    dp = [[0] * (n + 1) for _ in range(m + 1)]

    # 初始化第一行和第一列
    for i in range(m + 1):
        dp[i][0] = i  # 从dna1到空字符串的操作数为i(删除操作)
    for j in range(n + 1):
        dp[0][j] = j  # 从空字符串到dna2的操作数为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] + 1,      # 删除操作
                               dp[i][j - 1] + 1,      # 插入操作
                               dp[i - 1][j - 1] + 1)  # 替换操作

    return dp[m][n]  # 返回最终的编辑距离

if __name__ == "__main__":
    #  You can add more test cases here
    print(solution("AGCTTAGC", "AGCTAGCT") == 2 )
    print(solution("AGCCGAGC", "GCTAGCT") == 4)