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

相关推荐
用户447103089324211 小时前
详解前端框架中的设计模式 | 豆包MarsCode AI刷题
青训营笔记
用户58368380067612 小时前
学习笔记22《易速鲜花聊天客服机器人的开发(上)》
青训营笔记
用户2856200171318 小时前
寻找观光景点组合的最高得分| 豆包MarsCode AI 刷题
青训营笔记
用户48486281292222 天前
LangChain启程篇 | 豆包MarsCode AI刷题
青训营笔记
用户1538734266802 天前
前端框架中的设计模式解析
青训营笔记
努力的小Qin4 天前
小T的密码变换规则(青训营X豆包MarsCode) | 豆包MarsCode AI 刷题
青训营笔记
liangxiu4 天前
CSS布局技巧汇总| 豆包MarsCode AI刷题
青训营笔记
夭要7夜宵11 天前
Go 垃圾回收 | 豆包MarsCode AI刷题
青训营笔记
末班车42212 天前
前端框架中的设计模式 | 豆包MarsCode AI刷题
青训营笔记
VanceLLF12 天前
神奇数字组合 | 豆包MarsCode AI刷题
青训营笔记