动态规划之LCS算法

article/2025/9/11 11:06:02

一、前言

LCS是Longest Common Subsequence的缩写,即最长公共子序列。一个序列,如果是两个或多个已知序列的子序列,且是所有子序列中最长的,则为最长公共子序列。
另外还有个分支问题:最长公共子串。子串的字符位置必须连续,而子序列则不必,从原序列中去掉任意的元素获得的新序列。可以看出,子串问题比子序列问题要简单地多,子串必定是子序列,换言之,子串是子序列的子集。如果我们能解决子序列问题,子串问题也迎刃而解。

二、解法

2.1穷举法

穷举法是显而易见第一时间从脑子里蹦出来的想法,实际上代码层面的实现也不困难。提取出A序列的每一个子序列,检查其是否也是B序列的子序列,全部比对完后,比较出最长的一个子序列。
不考虑子序列重复的前提下啊,一个长度为n的序列,其子序列个数为2^n(容易理解,每一项取或不取)。易知其时间复杂度为O(2^n),指数级复杂度一般来说是不可接受的。
这里的空间复杂度我看一些文章说也是O(2^n),但是我觉得并不需要存下每一个子序列,每一个A的子序列经验证不是B的子序列后即可丢弃,所以存储的花费并不是所有子序列,而是所有公共子序列。所以我认为空间复杂度没有达到O(2^n),可能是我的理解有问题,如果有懂得观众看到这里,恳请指点一二。

2.2动态规划

X = [x1,x2,...,xm]Y = [y1,y2,...,yn]的一个最长公共子序列Z = [z1,z2,...,zk],则有:
1. 若xm=yn,则zk=xm=yn且Zk-1是Xm-1和Yn-1的最长公共子序列;
2. 若xm≠yn且zk≠xm,则Z是Xm-1和Y的最长公共子序列;
3. 若xm≠yn且zk≠yn,则Z是X和Yn-1的最长公共子序列。
其中Xm-1 = [x1, x2, …, xm-1]Yn-1 = [y1, y2, …, yn-1]Zk-1 = [z1, z2, …, zk-1]
第2点和第3点可以合并为,max(LCS(Xm-1,Yn),LCS(Xm,Yn-1))

2.3矩阵思想解题

记一个二维数组C[],c[i,j]存储Xi和Yi的最长公共子序列的长度。所以c[m,n]即矩阵最右下角的值为X与Y的最长公共子序列的长度。
虽然我们在递推过程是从序列的尾部开始的,但实际解题是从头部开始的,因为在计算max(LCS(Xm-1,Yn),LCS(Xm,Yn-1))时,需要事先计算出LCS(Xm-1,Yn)LCS(Xm,Yn-1),才能比较他们的大小。
1. 先令c[i,0]整一列的值为0,显然任意序列与空序列的最长公共子序列长度为0;同理,令c[0,j]整一行的值为0;
2. 如果当前比较的两个字符xi=yj,令这个格子的c[i,j] = 1。方向为左上角(LeftTop);
3. 如果当前比较的两个字符xi≠yj,比较c[i-1,j]和c[i,j-1]的值,取其中较大的值填充入c[i,j]中,方向为值的来源方向左(Left)或者上(Top);
4. 一直迭代运算至二维数组C[]所有格子均有值,结束。
便于理解抄自网络的图:
这里写图片描述

2.4小结

记录方向是为了构造出最长公共子序列,当然这样的算法有一个局限就是当LCS(Xm-1,Yn) = LCS(Xm,Yn-1)时会出现多解,即最长公共子序列不唯一。这样的情况显然是可预见的,所以在当出现LCS(Xm-1,Yn) = LCS(Xm,Yn-1)时两个方向都得记录,才能恢复出所有的最长公共子序列(如果有需要)。
当然,如果只是为了求得最长公共子序列的长度,方向是不必记录的。连矩阵都可以不用构造,因为c[i,j]的值完全来源于上一行的值,即c[i-1,j-1]、c[i-1,j]、c[i,j-1]三者其中之一,只需要记录矩阵中的两行数据即可,空间复杂度进一步降低。

2.5子问题1——最长公共子串

解决了最长公共子序列问题,最长公共子串就简单地多了。仍然是构造二维矩阵C[],当xi = yj时,令c[i,j] = c[i-1,j-1],然后矩阵中最大的元素就是最长公共子串的长度。构造最长公共子串也只需要找出最长的一条斜对角线即可。
附Python实现:

def find_lcs_len(input_x, input_y):dp = [([0] * len(input_y)) for i in range(len(input_x))]maxlen = 0for i in range(0, len(input_x)):for j in range(0, len(input_y)):if input_x[i] == input_y[j]:if i != 0 and j != 0:dp[i][j] = dp[i - 1][j - 1] + 1if i == 0 or j == 0:dp[i][j] = 1if dp[i][j] > maxlen:maxlen = dp[i][j]return maxlen

2.6子问题2——最长递增子序列(LIS)

看到这有些人可能会疑惑,最长递增子序列只关系到一个序列。如序列X = [5,8,2,3,9,4,7]的LIS为[2,3,4,7]。而LCS问题是两个序列的公共子序列问题。
其实这里先构造一个辅助序列X' = [2,3,4,5,7,8,9],即对X排序生成的新序列。对序列X和X’求LCS就是这个问题的解。这里不再详细论述,相信聪明的读者都容易看懂其中逻辑。

三、总结

用LCS算法代替穷举法来解决最长公共子序列问题,时间复杂度由O(2^n)下降到了O(n*m),空间复杂度也是同等级数的下降。经由精妙的LCS算法,为我们方便地解决了运算起来繁复的问题。
有机会得继续学习这些有趣奇妙的算法。另外,我也得花时间去理解下复杂度的计算,之前一直是我的盲点。
收!


http://chatgpt.dhexx.cn/article/F7WiCaar.shtml

相关文章

LCS算法的C++实现

这两天忙里偷闲看了July的团队提供的LCS算法视频,真的如视频标题一样,十分钟搞定LCS算法。 感谢July大神,感谢其团队的邹博。 这里附上视频链接:http://www.julyedu.com/video/play?course17 说是十分钟搞定,其实是…

算法学习 - 最长公共子序列(LCS)C++实现

最长公共子序列 最长公共子序列的问题很简单,就是在两个字符串中找到最长的子序列,这里明确两个含义: 子串:表示连续的一串字符 。子序列:表示不连续的一串字符。 所以这里要查找的是不连续的最长子序列, …

SLIC算法介绍

SLIC(simple linear iterativeclustering),即 简单线性迭代聚类 。 💛它是2010年提出的一种思想简单、实现方便的算法,将彩色图像转化为CIELAB颜色空间和XY坐标下的5维特征向量,然后对5维特征向量构造距离度…

LSC算法

1.问题 给定序列 X<x_1,x_2,…,x_m> Y<y_1,y_2,…,y_j> 求X和Y的最长公共子序列(LCS) 2.解析 X<x1,x2,x3,x4…,xi> Y<y1,y2,y3,y4…,yi> 如果Z<z1,z2,z3,z4…,zk>是他们的最长公共子序列 则&#xff1a; &#xff08;1&#xff09;xi yi&…

LCS算法详解

程序员编程艺术第十一章&#xff1a;最长公共子序列(LCS)问题 0、前言 程序员编程艺术系列重新开始创作了&#xff08;前十章&#xff0c;请参考程序员编程艺术第一~十章集锦与总结&#xff09;。回顾之前的前十章&#xff0c;有些代码是值得商榷的&#xff0c;因当时的代码只顾…

LCS 最大公共序列算法

这些天在了解chrome的courgette, 了解了rsync算法, 也了解了courgette使用了bsdiff 算法, 然后知道了bsdiff算法里主要使用的是 LCS 算法, 这里参考了july大牛的文章: http://blog.csdn.net/v_july_v/article/details/6695482 自己做一点概括性的总结, 用以备忘, 也把自…

最长公共子序列(LCS)算法

一、最长公共字串与最长公共子序列 最长公共子串&#xff08;Longest Common Substirng&#xff09; 子串是串的一个连续的部分&#xff0c;子串中字符的位置必须连续。 例如&#xff1a;有两个字符串ABCBDAB 和 BDCABA&#xff0c;则它们的最长公共子串是&#xff1a;AB。 …

LCS(longest common sequence)算法的实现(十分详细)

一、问题描述 有两个字符串&#xff0c;求二者的最长公共子序列。 最长公共子序列&#xff1a;不必连续但必须有序的子列&#xff08;与子串区分&#xff0c;子串是连续的&#xff09; 二&#xff1a;解决方法 第一种方法&#xff1a;穷举法 &#xff0c;就是一个一个的对比&a…

LCS算法

LCS算法 LCS算法&#xff1a; LCS是Longest Common Subsequence的缩写&#xff0c;即最长公共子序列。一个序列&#xff0c;如果是两个或多个已知序列的子序列&#xff0c;且是所有子序列中最长的&#xff0c;则为最长公共子序列。LCS不是唯一的&#xff0c;它可以有很多种&am…

Oracle中索引的原理

索引的概念 索引是一种数据库结构&#xff0c;能够就数据库中的某列提供快速查询&#xff0c;而不用检索整个表格&#xff08;官方的不行&#xff09;。 在 Oracle 数据库中&#xff0c;存储的每一行数据都有一个 rowID 来标识。当 Oracle 中存储着大量的数据时&#xff0c;意…

MongoDB索引原理及实践

背景 数据库的演进 随着计算机的发展&#xff0c;越来越多的数据需要被处理&#xff0c;数据库是为处理数据而产生。从概念上来说&#xff0c;数据库是指以一定的方式存储到一起&#xff0c;能为多个用户共享&#xff0c;具有更可能小的冗余&#xff0c;与应用程序彼此独立的…

MySql存储引擎和索引原理

转载 https://blog.csdn.net/tongdanping/article/details/79878302 注意&#xff1a; 1、索引需要占用磁盘空间&#xff0c;因此在创建索引时要考虑到磁盘空间是否足够 2、创建索引时需要对表加锁&#xff0c;因此实际操作中需要在业务空闲期间进行 MySQL支持诸多存储引擎&a…

MySQL之索引原理

1 简介 索引底层就是一种数据结构&#xff0c;空间换时间&#xff0c;能够帮助我们快速定位到对应的数据&#xff0c;就类似于字典里面的目录一样。 索引虽然能快速检索数据&#xff0c;但会影响数据修改的操作&#xff0c;而且索引存储在具体的文件&#xff0c;占用一定的空…

深入浅出数据库索引原理

使用索引很简单&#xff0c;只要能写创建表的语句&#xff0c;就肯定能写创建索引的语句&#xff0c;要知道这个世界上是不存在不会创建表的服务器端程序员的。然而&#xff0c; 会使用索引是一回事&#xff0c; 而深入理解索引原理又能恰到好处使用索引又是另一回事&#xff0…

MySQL索引原理和实现

说到索引&#xff0c;很多人都知道“索引是一个排序的列表&#xff0c;在这个列表中存储着索引的值和包含这个值的数据所在行的物理地址&#xff0c;在数据十分庞大的时候&#xff0c;索引可以大大加快查询的速度&#xff0c;这是因为使用索引后可以不用扫描全表来定位某行的数…

倒排索引原理,即为什么叫倒排索引

倒排索引的英文原名是Inverted index&#xff0c;大概因为Invert有颠倒的意思&#xff0c;所以就被翻译成了倒排&#xff0c;然后我们就会在字面上出现误解&#xff1a;理解为从A-Z颠倒成Z-A。其实它并不是字面上的意思。 倒排索引源于实际应用中需要根据属性的值来查找记录&a…

【数据库】数据库索引原理

正确的创建合适的索引 是提升数据库查询性能的基础 文章目录 1.索引是什么&#xff1f;2.为什么&#xff1f;3.索引原理B tree 4.B tree 在两大引擎中的体现5.索引的原则 1.索引是什么&#xff1f; 索引是为了加速对表中数据行的检索而创建的一种分散存储的数据结构。 2.为…

Mysql数据库的索引原理

写在前面&#xff1a;索引对查询的速度有着至关重要的影响&#xff0c;理解索引也是进行数据库性能调优的起点。考虑如下情况&#xff0c;假设数据库中一个表有10^6条记录&#xff0c;DBMS的页面大小为4K&#xff0c;并存储100条记录。如果没有索引&#xff0c;查询将对整个表进…

MySql索引原理与使用大全

林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka 一、索引介绍 索引是对数据库表中一列或多列的值进行排序的一种结构。在关系数据库中&#xff0c;索引是一种与表有关的数据库结构&#xff0c;它可以使对应于表的SQL语句执行得更快。索引的作用相…

MySQL:索引原理

文章目录 1、索引概念1.1、使用场景1.2、索引代价 2、索引分类2.1、数据结构2.2、物理存储回表查询 & 覆盖索引 2.3、字段&#xff08;列&#xff09;属性2.3.1、主键索引主键的选择 2.3.2、唯一索引2.3.2、普通索引2.3.3、前缀索引 2.4、字段&#xff08;列&#xff09;个…