AI刷题-动态规划“DNA序列编辑距离” | 豆包MarsCode AI刷题

题目解析

题目

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

解析

这是一个典型的动态规划问题 将dna1转换为dna2有三种方法 1.增加一个碱基 2.删除一个碱基 3.替换一个碱基 我们采用二维数组dp[i][j]来表示将dna1的前i个字符转换为dna2的前j个字符所需要的编辑次数

js 复制代码
    dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]

具体解法

当dna1的前i个字符和dna2的前j个字符相同时,不需要进行编辑 此时有: dp[i][j] = dp[i-1][j-1] 即: 将dna1的前i个字符编辑为dna2的前j个字符所需要的次数等于将dna1的前i-1个字符编辑为dna2的前j-1个字符所需要的次数

js 复制代码
if dna1[i - 1] == dna2[j - 1]:  # 字符相同,不需要操作
                dp[i][j] = dp[i - 1][j - 1]

当dna1的前i个字符和dna2的前j个字符不同时,需要进行编辑

对于三种编辑方法来说

增加一个碱基

当dna1的前i个字符和dna2的前j-1个字符相同时,采用增加一个碱基的方法会使编辑次数最少 此时有:

js 复制代码
dp[i][j] = dp[i][j-1]+1 

即: 将dna1的前i个字符编辑为dna2的前j个字符所需要的次数等于将dna1的前i个字符编辑为dna2的前j-1个字符所需要的次数+1

删除一个碱基

当dna1的前i-1个字符和dna2的前j个字符相同时,采用删除一个碱基的方法会使编辑次数最少 此时有:

js 复制代码
dp[i][j] = dp[i-1][j]+1 

即: 将dna1的前i个字符编辑为dna2的前j个字符所需要的次数等于将dna1的前i-1个字符编辑为dna2的前j个字符所需要的次数+1

替换一个碱基

当dna1的前i-1个字符和dna2的前j-1个字符相同时,采用替换一个碱基的方法会使编辑次数最少 此时有:

js 复制代码
dp[i][j] = dp[i-1][j-1]+1 

即: 将当dna1的前i个字符编辑为dna2的前j个字符所需要的次数等于将当dna1的前i-1个字符编辑为dna2的前j-1个字符所需要的次数+1

dp初始化

对于dp数组来说,

js 复制代码
dp[0][0] = 0

即将dna1的前0个字符编辑为dna2的前0个字符所需要的次数等于0

js 复制代码
dp[i][0] = i 

即将dna1的前i个字符编辑为dna2的前0个字符所需要的次数等于i(删除dna1的i个字符)

js 复制代码
 dp[0][j] = j

即将dna1的前0个字符编辑为dna2的前j个字符所需要的次数等于i(向dna1增加dna2的j个字符)

填充dp表

从dp数组的开头开始进行最小编辑次数的计算,将dp赋值为三种编辑方法中最小的数值

js 复制代码
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 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)  # 替换

最终返回dp[len1][len2]的值,即为将dna1转换为dna2所需的最小编辑次数

代码

js 复制代码
def solution(dna1, dna2):
    # 获取两个DNA序列的长度
    len1, len2 = len(dna1), len(dna2)
    
    # 创建一个二维数组来存储编辑距离
    dp = [[0] * (len2 + 1) for _ in range(len1 + 1)]
    
    # 初始化边界条件
    for i in range(len1 + 1):
        dp[i][0] = i  # 删除所有字符
    for j in range(len2 + 1):
        dp[0][j] = j  # 添加所有字符
    
    # 填充dp表
    for i in range(1, len1 + 1):
        for j in range(1, len2 + 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[len1][len2]

if __name__ == "__main__":
    print(solution("AGT", "AGCT") == 1)
    print(solution("AACCGGTT", "AACCTTGG") == 4)
    print(solution("ACGT", "TGC") == 3)
    print(solution("A", "T") == 1)
    print(solution("GGGG", "TTTT") == 4)

参考内容

[轻松掌握动态规划]6.编辑距离_哔哩哔哩_bilibili

相关推荐
柠檬柠檬1 小时前
Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题
青训营笔记
用户967136399651 小时前
计算最小步长丨豆包MarsCodeAI刷题
青训营笔记
用户529757993547217 小时前
字节跳动青训营刷题笔记2| 豆包MarsCode AI刷题
青训营笔记
clearcold1 天前
浅谈对LangChain中Model I/O的见解 | 豆包MarsCode AI刷题
青训营笔记
夭要7夜宵1 天前
【字节青训营】 Go 进阶语言:并发概述、Goroutine、Channel、协程池 | 豆包MarsCode AI刷题
青训营笔记
用户336901104442 天前
数字分组求和题解 | 豆包MarsCode AI刷题
青训营笔记
dnxb1232 天前
GO语言工程实践课后作业:实现思路、代码以及路径记录 | 豆包MarsCode AI刷题
青训营笔记
热的棒打鲜橙2 天前
数字分组求偶数和 | 豆包MarsCode AI刷题
青训营笔记
JinY142 天前
Go 语言入门指南:基础语法和常用特性解析 | 豆包MarsCode AI刷题
青训营笔记