python数据结构与算法-动态规划(最长公共子序列)

这篇具有很好参考价值的文章主要介绍了python数据结构与算法-动态规划(最长公共子序列)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、最长公共子序列问题

1、问题概念

  • 一个序列的子序列是在该序列中删去若干元素后得 到的序列。

  • 例如:"ABCD”和“BDF”都是“ABCDEFG”的子序列。

  • 最长公共子序列(LCS) 问题: 给定两个序列X和Y,求X和Y长度最大的公共子字列。

  • 例:X="ABBCBDE”Y="DBBCDB”LCS(XY)="BBCD"

  • 应用场景:字符串相似度比对

2、问题求解思路

(1)问题思考

  • 思考: 暴力穷举法的时间复杂度是多少?

序列中的每一个值都有两种选择,被选择或者不被选择,因此一个长度为n的序列,其子序列为python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档种。求解长度为n和长度为m的序列的公共子序列,对比python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档个子序列之间的关系,是否相同,因此时间复杂度为O(python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档)

  • 思考: 最长公共子序列是否具有最优子结构性质?

有,见解最优子结构

(2)最优子结构

(LCS的最优子结构):令X=(python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,......,python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档)和Y=(python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,......,python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档)为两个序列,Z=(python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,......,python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档)为X和Y的任意 LCS。

  • 如果python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档 = python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,则python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档 = python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档 = python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档的一个LCS。

例如:序列ABCD和ABD,其LCS为ABD,此时python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档 = python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档 = python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档=D,可见,AB是ABC和AB的LCS。

  • 如果python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,且python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档意味着Z是python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档和Y的一个LCS。

例如:序列ABCD和ABC,其LCS为ABC,此时python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,即D与C不相等,则python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档为ABC,可见,ABC是ABC和ABC的LCS。

  • 如果python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,且python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档意味着Z是X和python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档的一个LCS。

例如:序列ABC和ACD,其LCS为AC,此时python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档,即D与C不相等,则python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档为AC,可见,AC是ABC和AC的LCS。

示例如下:

要求a="ABCBDAB"与b="BDCABA"的LCS:

  • 由于最后一位"B“≠"A”:

  • 因此LCS(a,b)应该来源于LCS(a[:-1],b)与LCS(a,b[:-1])中更大的那一个

(3)问题递推式

1)递推式推理说明

python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档

结合最优子结构的定理,可以得到以上的图。

举例解析:

  • x0都是空列表,y0也是空列表,因此与x0或者y0的LCS一定是0。

  • 序列BDC和序列A:C != A,则LCS来源与LCS([BDC],[ ])和LCS([BD],[A])中,图中可看出,两者都为0,即LCS([BDC], [A])的左边和上边的位置。

  • 序列BDCA和序列A:A = A,则A一定是两个序列的LCS中的一个元素,且LCS([BDC], [A])加上元素A就是LCS([BDCA], [A])。查看可知,LCS([BDC], [A]) = 0,所以LCS([BDCA], [A]) = 0 + 1(元素A)。

  • 剩余的同理。

2)递推式

python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档

c[i,j]表示python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档python最长公共子序列,python数据结构与算法,动态规划,算法,python,Powered by 金山文档的LCS长度

二、最长公共子序问题代码实现

1、最长公共子序长度求解


def lcs_length(x,y): # 公共子序列长度,x,y: 字符串、列表等序列
    m = len(x) # x序列长度
    n = len(y) # y序列长度
    c = [[0 for i in range(n + 1)] for _ in range(m+1)] # 创建m行n列二维数组,初始值为0 
    for i in range(1, m+1):  # 按数组的行求,x0都为0不用求,所以从1开始
        for j in range(1, n+1): # 数组每行中的遍历,y0都为0,不用求
            if x[i - 1] == y[j - 1]:  # x[i-1]其实是字符串的i,因为i=0在二维列表中都是0,不求解,但是在字符串中仍需要从索引0遍历
                c[i][j] = c[i-1][j-1] + 1 # 递推式
            else:  # xi!=yi
                c[i][j] = max(c[i-1][j],c[i][j-1])  # 递推式
    
    return c[m][n]    # x和y的最后一个元素对比完,二维数组的最后一位

print(lcs_length('ABCBDAB', 'BDCABA'))

输出结果

4

2、最长公共子序的序列求解

动态规划+ 回溯算法搭配使用,动态规划求解最优值,回溯法推算出过程的解。

(1)动态规划求解并存储解-代码实现

# 动态规划求解,存储解及解的计算过程
def lcs(x,y): # 求解并存储箭头方向,x,y为字符串、列表等序列
    m = len(x) # x的长度
    n = len(y) # y的长度
    c = [[0 for i in range(n+1)] for _ in range(m+1)] # 二维数组,初始值为0,用于存储长度结果
    d = [[0 for i in range(n+1)] for _ in range(m+1)] # 二维数组,初始值为0,用于存储箭头方向,1表示左上,2表示上,3表示左
    for i in range(1,m+1): # 按行遍历二维数组
        for j in range(1,n+1): # 每行的各数值遍历, c0j和ci0相关的值都为0,所以均从1开始
            if x[i - 1] == y[j - 1]: # xi=yi的情况,二维数组中i,j=0时,都为0已经确定,但字符串x,y仍需从0开始遍历
                c[i][j] = c[i - 1][j - 1] + 1 # 递推式
                d[i][j] = 1 # 箭头方向左上方
            elif c[i][j - 1] > c[i - 1][j]: # 递推式,选择更大的
                c[i][j] = c[i][j - 1]
                d[i][j] = 3 # 箭头左边
            else: # c[i-1][j] >= c[i][j-1]
                c[i][j] = c[i - 1][j]
                d[i][j] = 2 # 箭头上方
    return c[m][n], d

c, d = lcs("ABCBDAB", "BDCABA")
for _ in d:
    print(_)

输出结果:

[0, 0, 0, 0, 0, 0, 0]
[0, 2, 2, 2, 1, 3, 1]
[0, 1, 3, 3, 2, 1, 3]
[0, 2, 2, 1, 3, 2, 2]
[0, 1, 2, 2, 2, 1, 3]
[0, 2, 1, 2, 2, 2, 2]
[0, 2, 2, 2, 1, 2, 1]
[0, 1, 2, 2, 2, 1, 2]

(2)回溯算法的应用-代码实现

# 动态规划求解,存储解及解的计算过程
def lcs(x,y): # 求解并存储箭头方向,x,y为字符串、列表等序列
    m = len(x) # x的长度
    n = len(y) # y的长度
    c = [[0 for i in range(n+1)] for _ in range(m+1)] # 二维数组,初始值为0,用于存储长度结果
    d = [[0 for i in range(n+1)] for _ in range(m+1)] # 二维数组,初始值为0,用于存储箭头方向,1表示左上,2表示上,3表示左
    for i in range(1,m+1): # 按行遍历二维数组
        for j in range(1,n+1): # 每行的各数值遍历, c0j和ci0相关的值都为0,所以均从1开始
            if x[i - 1] == y[j - 1]: # xi=yi的情况,二维数组中i,j=0时,都为0已经确定,但字符串x,y仍需从0开始遍历
                c[i][j] = c[i - 1][j - 1] + 1 # 递推式
                d[i][j] = 1 # 箭头方向左上方
            elif c[i][j - 1] > c[i - 1][j]: # 递推式,选择更大的
                c[i][j] = c[i][j - 1]
                d[i][j] = 3 # 箭头左边
            else: # c[i-1][j] >= c[i][j-1]
                c[i][j] = c[i - 1][j]
                d[i][j] = 2 # 箭头上方
    return c[m][n], d

# 回溯算法
def lcs_trackback(x,y): # 最长公共子序列的序列
    c, d = lcs(x, y) # c长度,d箭头方向
    i = len(x) # x的长度
    j = len(y) # y的长度
    res = [] # 结果列表
    while i > 0 and j > 0 : # 序列x和y还有值未比对,任何一个序列为0了都不再继续
        if d[i][j] == 1: # 箭头左上方 ——> 匹配
            res.append(x[i - 1])  # 二维列表中i=0时,值为0,但是序列x的值是从0开始遍历的
            i = i - 1 # 位置移到左上位置
            j = j - 1
        elif d[i][j] == 2: # 箭头上方->不匹配
            i = i - 1 # 位置往上移一格
        else: # dij = 3 ,箭头左向
            j = j - 1 # 位置往左移一格
    
    return "".join(reversed(res))  # 列表翻转,并将列表用''连接成字符串

print(lcs_trackback("ABCBDAB", "BDCABA"))

结果输出文章来源地址https://www.toymoban.com/news/detail-717554.html

BCBA

到了这里,关于python数据结构与算法-动态规划(最长公共子序列)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【零基础】学python数据结构与算法笔记14-动态规划

    学习python数据结构与算法,学习常用的算法, b站学习链接 动态规划在基因测序、基因比对、hmm 有应用场景。 从斐波那契数列看动态规划 练习: 使用递归和非递归的方法来求解斐波那契数列。 这种非递归求斐波那契数,可以看成是一个动态规划思想,每次都会把重复子问

    2023年04月09日
    浏览(31)
  • 数据结构与算法-动态规划

    (我猜是做的多了背的题多了就自然懂了) 迭代法一般没有通用去重方式,因为已经相当于递归去重后了 这两个问题其实是一个问题,一般直接写出的没有去重的递归法,复杂度很高,此时需要使用备忘录去重,而备忘录去重时间复杂度和使用dp数组进行迭代求解时间复杂度相同

    2024年02月04日
    浏览(34)
  • 数据结构与算法之贪心&动态规划

            一:思考         1.某天早上公司领导找你解决一个问题,明天公司有N个同等级的会议需要使用同一个会议室,现在给你这个N个会议的开始和结束 时间,你怎么样安排才能使会议室最大利用?即安排最多场次的会议?电影的话 那肯定是最多加票价最高的,入场

    2024年02月09日
    浏览(38)
  • 数据结构与算法 | 动态规划算法(Dynamic Programming)

    上一篇文末已经提到了记忆化搜索是动态规划(Dynamic Programming)的一种形式,是一种自顶向下(Top-Down)的思考方式,通常采用递归的编码形式;既然动态规划有自顶向下(Top-Down)的递归形式,自然想到对应的另外一种思考方式 自底向上( Bottom-Up ) ,也就是本篇要写的内

    2024年02月05日
    浏览(33)
  • Java数据结构与算法----动态规划(背包篇)

    1.1.算法思路 0/1背包是动态规划、背包问题中最经典的问题啦!它主要的问题是: 给定n种物品、这n种物品的重量分别是,价值分别是 ,而你有一个容量为C的背包,请问如何求出所能拿的最大价值呢? 对于动态规划,我们先需要找到一条推导公式,然后确定边界: 我们设

    2024年02月07日
    浏览(37)
  • 数据结构与算法:动态规划(Dynamic Programming)详解

    动态规划(Dynamic Programming,简称DP) 是一种在数学、管理科学、计算机科学、经济学和生物信息学等领域中使用的,通过把原问题分解为相对简单的子问题的方式求解复杂问题的方法。动态规划经常被用于求解优化问题。 动态规划的核心思想是将复杂问题分解为更小的子问

    2024年04月25日
    浏览(37)
  • 【夜深人静学数据结构与算法 | 第十篇】动态规划

    目录 前言: 动态规划: 常见应用: 解题步骤:  动态规划的简化步骤: 案例: 509. 斐波那契数 - 力扣(LeetCode) 70. 爬楼梯 - 力扣(LeetCode) 62. 不同路径 - 力扣(LeetCode) 总结:         本文我们将为大家讲解一下动态规划的理论知识,并且会讲解几道力扣的经典例题。

    2024年02月11日
    浏览(45)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包