【2024字节青训·易】DNA序列还原

【2024字节青训·易】DNA序列还原

问题描述

给定一段受损的 DNA 碱基序列 dna1,在每次只操作一个碱基的情况下,将其以最少的操作步骤将其还原到未受损的 DNA 碱基序列 dna2。

只可以对 DNA 碱基序列中的一个碱基进行三种操作:

  1. 增加一个碱基
  2. 去除一个碱基
  3. 替换一个碱基

输入描述:

输入两段 DNA 碱基序列,每段分一行输入

第一行为第一段受损的 DNA 碱基序列 dna1

第二行为第二段未受损的 DNA 碱基序列 dna2

输出描述:

最小操作步骤数

备注:

0 <= dna1.length, dna2.length <= 500

dna1 和 dna2 由大写英文字母 A、G、C、T 组成

示例 1

输入

AGCTTAGC

AGCTAGCT

输出

2

说明

AGCTTAGC -> AGCTAGC(删除 T)

AGCTAGC -> AGCTAGCT(增加 T)

示例 2

输入

AGCCGAGC

GCTAGCT

输出

4

说明

AGCCGAGC -> GCCGAGC(删除 A)

GCCGAGC -> GCTGAGC(将 C 替换为 T)

GCTGAGC -> GCTAGC(删除 G)

GCTAGC -> GCTAGCT(增加 T)

要解决这个问题,我们可以使用动态规划(Dynamic Programming, DP)的方法。这个方法非常适合解决涉及字符串编辑距离的问题,比如 DNA 碱基序列的转换。我们将使用经典的编辑距离算法(也称为莱文斯坦距离算法)。

动态规划方法

我们定义一个二维数组 dp,其中 dp[i][j] 表示将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最小操作数。

状态转移方程

  1. 初始状态

    • dp[0][0] = 0,因为将空字符串转换为空字符串不需要任何操作。
    • dp[i][0] = i,因为将前 i 个字符的 dna1 转换为空字符串需要 i 次删除操作。
    • dp[0][j] = j,因为将空字符串转换为前 j 个字符的 dna2 需要 j 次插入操作。
  2. 状态转移方程

    • 如果 dna1[i-1] == dna2[j-1],则 dp[i][j] = dp[i-1][j-1],因为最后一个字符相同,不需要额外操作。

    • 如果

      dna1[i-1] != dna2[j-1]
      

      ,则需要考虑三种操作:

      • 插入操作:dp[i][j] = dp[i][j-1] + 1
      • 删除操作:dp[i][j] = dp[i-1][j] + 1
      • 替换操作:dp[i][j] = dp[i-1][j-1] + 1
    • 综合起来就是:

    • d p [ i ] [ j ] = min ⁡ ( d p [ i − 1 ] [ j ] + 1 , d p [ i ] [ j − 1 ] + 1 , d p [ i − 1 ] [ j − 1 ] + ( d n a 1 [ i − 1 ] ≠ d n a 2 [ j − 1 ] ) ) dp[i][j] = \min(dp[i-1][j] + 1, dp[i][j-1] + 1, dp[i-1][j-1] + (dna1[i-1] \neq dna2[j-1])) dp[i][j]=min(dp[i1][j]+1,dp[i][j1]+1,dp[i1][j1]+(dna1[i1]=dna2[j1]))

def solution(dna1, dna2):
    m, n = len(dna1), len(dna2)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    
    for i in range(1, m+1):
        dp[i][0] = i
    for j in range(1, n+1):
        dp[0][j] = j

    dp[0][0] = 0
    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)
    
    # Please write your code here
    return dp[m][n]

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值