一、前言

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算法,为我们方便地解决了运算起来繁复的问题。
有机会得继续学习这些有趣奇妙的算法。另外,我也得花时间去理解下复杂度的计算,之前一直是我的盲点。
收!

动态规划之LCS算法相关推荐

  1. 改进的LCS算法的应用

    笔者在做毕设的时候遇到过一种有趣的近义词识别问题.该问题是想简化每种岗位里的技能实体的数量,比如说java开发工程师里有(java开源框架)和(java相关框架)这两个相似的技能实体.也许有人会认为直 ...

  2. 动态规划法和贪心算法

    动态规划法和贪心算法 csdn第一篇blog. 先说说写文章的好处: 第一,写文章是个学习的过程.写的过程中随着自己的思路的进行,会出现理解不清楚的地方,自然就会翻书或者google的搞明白. 第二, ...

  3. LCS算法:最长公共子序列

    LCS算法:最长公共子序列定义: 一个序列A任意删除若干个字符得到新序列B,则A叫做B的子序列 两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列 例如: X={A,B,C,B ...

  4. 最长公共子序列问题——LCS算法

    最长公共子序列问题--LCS算法 问题描述: 给出两个字符串A B,求A与B的最长公共子序列(子序列不要求是连续的).比如两个串为:abcicba abdkscabab是两个串的子序列,abc也是,a ...

  5. 动态规划与贪心算法比较

    动态规划和贪心算法比较 动态规划: 动态规划一般分为线性动规.区域动规.树形动规.背包动规四类 动态规划程序设计师是对解最优化问题的一种途径.一种方法,而不是一种特殊的算法,并不是一个标准的数学表达式 ...

  6. JavaScript实现递归楼梯问题(动态规划解决方案)算法(附完整源码)

    JavaScript实现递归楼梯问题(动态规划解决方案)算法(附完整源码) recursiveStaircaseDP.js完整源代码 recursiveStaircaseDP.test.js完整源代码 ...

  7. JavaScript实现MaximumSubarray最大子阵列(动态规划解决方案)算法(附完整源码)

    JavaScript实现MaximumSubarray最大子阵列(动态规划解决方案)算法(附完整源码) dpMaximumSubarray.js完整源代码 dpMaximumSubarray.test ...

  8. 53. 最大子序和 golang (动态规划与贪心算法)

    题目 给定一个整数数组 nums ,找到一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和. 示例: 输入: [-2,1,-3,4,-1,2,1,-5,4], 输出: 6 解释: 连续 ...

  9. 活动安排问题的 动态规划和贪心算法

    这篇文章主要用来记录我对<算法导论> 贪心算法一章中的"活动选择问题"的动态规划求解和贪心算法求解 的思路和理解. 主要涉及到以下几个方面的内容: ①什么是活动选择问题 ...

  10. 从 活动选择问题 看动态规划和贪心算法的区别与联系

    这篇文章主要用来记录我对<算法导论> 贪心算法一章中的"活动选择问题"的动态规划求解和贪心算法求解 的思路和理解. 主要涉及到以下几个方面的内容: ①什么是活动选择问题 ...

最新文章

  1. js 使用 Lawnchair 存储 json 对象到本地
  2. 《Visual Studio Hacks 》(十)
  3. python解析库_Python命令行解析库argparse
  4. Python基础知识(第十一天)
  5. 散列表查找失败平均查找长度_Python数据结构与算法56:排序与查找:冲突解决方案...
  6. php下xmlwriter,PHP实现基于XMLWriter操作xml的方法
  7. Linux查看登录日志
  8. [Codeforces235D]Graph Game——概率与期望+基环树+容斥
  9. xss挖掘思路分享_WEB安全(二) :XSS的漏洞挖掘(上)
  10. 时间复杂度和空间复杂度1 - 数据结构和算法03
  11. windows 10 Office 2016 安装
  12. Win11用户好消息 影响win11性能运行的竟是它,关闭可提升性能
  13. PyQt4--QPushButton(click)类的信号
  14. 维基百科--文件系统大全
  15. for和if嵌套使用
  16. Qt实现双击可编辑的QLabel,输入文本后回车确定
  17. vue-transitionslotmixinfilterplugin
  18. 迁移学习笔记3: TCA, Finetune, 与Triplet Network(元学习)
  19. cad哪个版本最好用?思路提供
  20. TCP MSS PMTU PING

热门文章

  1. 计算机软件设计费计算标准,水利工程咨询、勘测设计费收费标准及计算程序
  2. mindoc快速搭建教程
  3. Win连接android打印机,教你用Android/Iphone/MacWindows和群晖实现无线打印
  4. 4 卷积的拉普拉斯变换
  5. Mac:如何配置java和maven环境变量
  6. VS+Qt应用开发-设置软件图标
  7. 日程表模板html,excel日程表模板(每日工作时间表模板)
  8. 改变世界的程序员—Jack Dorsey (程序员 2011-6)
  9. UG与PROE哪个好用,主要看是用在哪里
  10. 【java】java Jvm内存结构