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

news2024/12/24 2:56:19

一、最长公共子序列问题

1、问题概念

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

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

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

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

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

2、问题求解思路

(1)问题思考

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

序列中的每一个值都有两种选择,被选择或者不被选择,因此一个长度为n的序列,其子序列为种。求解长度为n和长度为m的序列的公共子序列,对比个子序列之间的关系,是否相同,因此时间复杂度为O()

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

有,见解最优子结构

(2)最优子结构

(LCS的最优子结构):令X=(,......,)和Y=(,......,)为两个序列,Z=(,......,)为X和Y的任意 LCS。

  • 如果 = ,则 = = 的一个LCS。

例如:序列ABCD和ABD,其LCS为ABD,此时 = = =D,可见,AB是ABC和AB的LCS。

  • 如果,且意味着Z是和Y的一个LCS。

例如:序列ABCD和ABC,其LCS为ABC,此时,即D与C不相等,则为ABC,可见,ABC是ABC和ABC的LCS。

  • 如果,且意味着Z是X和的一个LCS。

例如:序列ABC和ACD,其LCS为AC,此时,即D与C不相等,则为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)递推式推理说明

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

举例解析:

  • 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)递推式

c[i,j]表示的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"))

结果输出

BCBA

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/449312.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【ABAQUS Python二次开发】 debug : ini解析ERROR:没有实例属性‘__getintem__’

我的主页: 技术邻:小铭的ABAQUS学习的技术邻主页博客园 : HF_SO4的主页哔哩哔哩:小铭的ABAQUS学习的个人空间csdn:qgm1702 博客园文章链接: https://www.cnblogs.com/aksoam/p/17287136.html abaqus python 搭配ini…

古埃及:金字塔

文章目录 I 建造金字塔1.1 切割巨石1.2 开凿巨石1.3 摞石1.4 大金字塔的入口呈三角形 see also I 建造金字塔 在生活中,事实是正确的,如果理论解释不了现实,需要更正理论。 1.1 切割巨石 建筑材料巨石的切割:把石英砂粘在了铜锯…

记一次Macbook pro电池修复

记一次Macbook pro电池修复 mac版本 A1708 问题描述 Macbook更换新电池后,在项头栏中,没有显示电池图标,系统设置里面也找不到电池图标。这样开机还得连着电源线 ~ ^~ 原因分析: 有可能是电池排线坏了。 解决方案&#xff1a…

【C/C++】C++11 线程库重大历史意义

文章目录 C11 线程库重大意义【C11 中最重要的特性:就是对线程进行支持】API 比较C11 线程库APILinux/Win 系统线程库 API代码示例 Demo C11 线程库重大意义【C11 中最重要的特性:就是对线程进行支持】 C11 线程库解决了历史多线程跨平台问题&#xff0…

C++语法(20)---- 模拟红黑树

C语法(19)---- 模拟AVL树_哈里沃克的博客-CSDN博客https://blog.csdn.net/m0_63488627/article/details/130229501?spm1001.2014.3001.5501 目录 1.红黑树介绍 2.模拟实现 1.枚举红黑颜色 2.节点的定义 3.树类框架 4.插入 5.检查 3.代码实现 1…

【开发经验】spring事件监听机制关心的同步、异步、事务问题

文章目录 spring发布订阅示例同步核心源码分析如何配置异步事务问题 观察者模式又称为发布订阅模式,定义为:对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都得到通知并被自动更新。 如下图所示&…

【Go】六、并发编程

文章目录 并发编程1、并发介绍2、Goroutine3、runtime包 3、Channel3.1、channel相关信息 4、Goroutine池(❌)5、定时器6、select多路复用7、并发安全和锁8、Sync9、原子操作(atomic包) 并发编程 1、并发介绍 1、进程和线程 ​…

心塞,被面试官在朋友圈吐槽了

​前阵子一个后辈小学弟向我诉苦,说自己在参加某大厂测试的时候被面试官怼得哑口无言,场面让他一度十分尴尬。 印象最深的就是下面几个问题: 自动化测试中,如何解决Case依赖?你们公司业务中,自动化和手工分…

“五一”预订量创5年新高!如何制定营销活动引爆门店客流?

作为疫情3年经济复苏后,2023年的第一个长假,今年“五一”的消费需求将全面集中释放,带动全国各地线下实体生意全面复苏。 根据官方平台发布的数据显示,今年五一的旅游订单比疫情前的2019年增长了200%,是近5年预订量最多…

Spring Security 整体架构

Spring Security 整体架构 整体架构 在的架构设计中,认证 和 授权 是分开的,无论使用什么样的认证方式。都不会影响授权,这是两个独立的存在,这种独立带来的好处之一,就是可以非常方便地整合一些外部的解决方案。 认…

(数字图像处理MATLAB+Python)第五章图像增强-第三节:基于照度反射模型的图像增强

文章目录 一:基于同态滤波的增强(1)概述(2)程序 二:Retinex理论(1)Retinex理论概述(1)SSR(单尺度Retinex 算法)(2&#xf…

Oracle的学习心得和知识总结(二十二)|Oracle数据库Real Application Testing之Database Replay实操(二)

目录结构 注:提前言明 本文借鉴了以下博主、书籍或网站的内容,其列表如下: 1、参考书籍:《Oracle Database SQL Language Reference》 2、参考书籍:《PostgreSQL中文手册》 3、EDB Postgres Advanced Server User Gui…

操作系统概述及Linux基本指令(1)

目录 一. 操作系统 1.1 什么是操作系统 1.2 操作系统的核心工作 二. Linux的基本指令 2.1 ls指令 -- 打印文件名 2.2 pwd指令 -- 显示路径 2.3 cd指令 -- 进入特定目录 2.4 touch指令 -- 创建普通文件 2.5 mkdir指令 -- 创建路径 2.6 rmdir/rm指令 -- 删除路径或普通…

【GeoDjango框架解析】空间方法的ORM查询

原文作者:我辈理想 版权声明:文章原创,转载时请务必加上原文超链接、作者信息和本声明。 Django数据操作-ORM 第一章 【Django开发入门】ORM的增删改查和批量操作 第二章 【Django开发入门】ORM查询分页以及返回Json格式 文章目录 Django数据…

中国人民大学与加拿大女王大学金融硕士——在职读研该如何平衡学习与工作呢

边工作边考研,对于所有人来说都是个不小的挑战,每年都有大量在职生因为焦躁、压力而中途离场。学习时间碎片化,复习进度特别容易被工作上的事情所打断,再想“重新启动”就会很难。想要节省备考时间建议你读免联考的中外合作办学项…

基于Canvas实现图片的上传和渲染

1 Canvas 1.1 什么是Canvas 是一个可以使用脚本 (通常为JavaScript) 来绘制图形的 HTML 元素。例如&#xff0c;它可以用于绘制图表、制作图片构图或者制作简单的动画。 1.2 基本使用 宽高&#xff1a; <canvas id"tutorial" width"150" height&qu…

<C++>C++入门

目录 前言 一、C关键字&#xff08;C98&#xff09; 二、命名空间 1. 命名空间定义 2. 命名空间的使用 3. 命名空间的使用有三种方式&#xff1a; 三、C输入&输出 四、缺省参数 1. 缺省参数概念 2. 缺省参数的分类 3. 缺省参数的应用 五、函数重载 六、引用 1. 引用的概念…

web实验(2)

&#xff08;1&#xff09; 应用html标签和css完成如下所示页面效果&#xff0c;图片见附件。 说明&#xff1a; 内容相对于浏览器居中,宽860px鼠标移动至列表项上&#xff0c;显示背景色#F8F8F8分割线2px solid #ccc&#xff0c;每项高130px第一行文字&#xff1a;20px 黑体…

4.功能权限

基于角色的权限控制&#xff0c;用户分配角色&#xff0c;角色分配菜单。 1. 权限注解 1.基于【权限标识】的权限控制 权限标识&#xff0c;对应 system_menu 表的 permission 字段&#xff0c;推荐格式为 {系统}:{模块}:{操作}&#xff0c;例如说 system:admin:add 标识 sy…

chatgpt智能提效职场办公-ppt怎么做才好看又快

作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 制作ppt有几个方面可以考虑&#xff0c;以实现既好看又快速的目的&#xff1a; 使用模板&#xff1a;使用ppt模板可以更快速地制作出一…