最长公共子序列(LCS)
问题描述
子串应该比较好理解,至于什么是子序列,这里给出一个例子:有两个母串
- cnblogs
- belong
比如序列bo, bg, lg在母串cnblogs与belong中都出现过并且出现顺序与母串保持一致,我们将其称为公共子序列。最长公共子序列(Longest Common Subsequence,LCS),顾名思义,是指在所有的子序列中最长的那一个。子串是要求更严格的一种子序列,要求在母串中连续地出现。在上述例子的中,最长公共子序列为blog(cnblogs,belong),最长公共子串为lo(cnblogs, belong)。
求解算法
对于母串X=, Y=,求LCS与最长公共子串。
假设Z=是X与Y的LCS, 我们观察到:
- 如果Xm=Yn,则Zk=Xm=Yn,有:Zk−1是Xm−1与Yn−1的LCS;
- 如果Xm≠Yn,则Zk是Xm与Yn−1的LCS,或者是Xm−1与Yn的LCS。
因此,求解LCS的问题则变成递归求解的两个子问题。但是,上述的递归求解的办法中,重复的子问题多,效率低下。改进的办法——用空间换时间,用数组保存中间状态,方便后面的计算。这就是动态规划(DP)的核心思想了。
DP求解LCS
用二维数组ci记录串x1,x2,⋯,xi与y1,y2,⋯,yj的LCS长度,则可得到状态转移方程:
由最长公共子序列问题的最优子结构性质可知,要找出X=和Y=的最长公共子序列,可按以下方式递归地进行:当xm=yn时,找出Xm-1和Yn-1的最长公共子序列,然后在其尾部加上xm(=yn)即可得X和Y的一个最长公共子序列。当xm≠yn时,必须解两个子问题,即找出Xm-1和Y的一个最长公共子序列及X和Yn-1的一个最长公共子序列。这两个公共子序列中较长者即为X和Y的一个最长公共子序列。
在算法LCS中,每一次的递归调用使i或j减1,因此算法的计算时间为O(m+n)。
代码实现
int lcs(String str1, String str2) { int len1 = str1.length(); int len2 = str2.length(); int c[][] = new int[len1 + 1][len2 + 1]; for (int i = 0; i <= len1; i++) { for (int j = 0; j <= len2; j++) { if (i == 0 || j == 0) { c[i][j] = 0; } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) { c[i][j] = c[i - 1][j - 1] + 1; } else { c[i][j] = max(c[i - 1][j], c[i][j - 1]); } } } return c[len1][len2]; }

低调大师中文资讯倾力打造互联网数据资讯、行业资源、电子商务、移动互联网、网络营销平台。
持续更新报道IT业界、互联网、市场资讯、驱动更新,是最及时权威的产业资讯及硬件资讯报道平台。
转载内容版权归作者及来源网站所有,本站原创内容转载请注明来源。
- 上一篇
python学习之路——基础语法篇(2)之list
1. 定义 定义一个列表的方法有三种: a = ['zhangsan', 18, 'male'] # 第一种,直接用[] b = list(['zhangsan', 18, 'male']) # 第二种,用list函数,也可以写成b = list([1, 2, 3]) b = a # 第三种,用一个列表初始化另一个列表 c = a + b # 与第三种类似,可以用两个列表相加来初始化另一个列表 print(c)# ['zhangsan', 18, 'male', 'zhangsan', 18, 'male'] 需要注意的是第三种方法的赋值是浅拷贝,所以在修改数据时可能会出现问题:: a = ['zhangsan', 18, 'male', 'handsome', 100] b = a #浅拷贝 print(a,b)# a=['zhangsan', 18, 'male', 'handsome', 100] b=['zhangsan', 18, 'male', 'handsome', 100] b[0]='lisi' print(a,b)# a=['lisi', 18, 'male', '...
- 下一篇
jvm虚拟机中运行时数据区域介绍
jvm虚拟机中,运行时数据区域包括七大部分 i. 程序计算器 i. 定义 1) 极小的内存空间; 2) 行号指示器,程序的分支、循环、跳转、异常处理、线程恢复等基本功能都需要依赖程序计算器; 3) 线程私有的。 ii. 由来 因为java虚拟机的多线程是通过线程轮流切换并分配处理器执行时间的方式来实现的,在一个确定的时刻,一个cpu只执行一条线程中的指令;为了线程切换后能 恢复到正确的执行位置,每条线程都需要有一个独立的程序计数器,各线程之间计数器互不影响,独立存储,此内存为线程私有。 iii. 不同的使用场景 1) 线程执行的是java方法,计数器记录的是正在执行的虚拟机字节码指令的地址; 2) Native方法,计数器值为空; iv. 注意 在java虚拟机规范中唯一没有规定任何OutOfMemoryError情况的区域 ii. java虚拟机栈 i. 定义 1) 线程私有的,生命周期与线程相同; 2) 虚拟机栈描述的是java方法执行的内存模型:每个方法在执行的同时都会创建一个栈帧用于存储局部变量表、操作数栈、动态链接、方法出口等信息; 3) 方法的调用直至执行完成的过程,对应着...
相关文章
文章评论
共有0条评论来说两句吧...
文章二维码
点击排行
推荐阅读
最新文章
- Docker快速安装Oracle11G,搭建oracle11g学习环境
- CentOS7,8上快速安装Gitea,搭建Git服务器
- CentOS8安装MyCat,轻松搞定数据库的读写分离、垂直分库、水平分库
- SpringBoot2整合Thymeleaf,官方推荐html解决方案
- CentOS7,CentOS8安装Elasticsearch6.8.6
- CentOS关闭SELinux安全模块
- SpringBoot2初体验,简单认识spring boot2并且搭建基础工程
- Eclipse初始化配置,告别卡顿、闪退、编译时间过长
- SpringBoot2整合Redis,开启缓存,提高访问速度
- CentOS7设置SWAP分区,小内存服务器的救世主