算法练习——最长公共子序列的问题(LCS)
问题描述:
对于两个序列X和Y的公共子序列中,长度最长的那个,定义为X和Y的最长公共子序列。X Y 各自字符串有顺序,但是不一定需要相邻。
最长公共子串(Longest Common Substring ):顺序相同,并且各个字符的位置也必须相邻。
最长公共子序列(Longest Common Subsequence,LCS ):顺序形同,各个字符的位置不一定相邻。
比如:
字符串 13455 与 245576 的最长公共子序列为455
字符串 acdfg 与 adfc 的最长公共子序列为adf adf在acdfg中的顺序相同,但是不相邻。
1:暴力求解
即对X的每一个子序列,检查它是否也是Y的子序列,从而确定它是否为X和Y的公共子序列,并且在检查过程中选出最长的公共子序列。X和Y的所有子序列都检查过后即可求出X和Y的最长公共子序列。X的一个子序列相应于下标序列{1, 2, …, m}的一个子序列,因此,X共有2m个不同子序列(Y亦如此,如为2^n,每个元素都有取或者不取的情况),从而穷举搜索法需要指数时间(2^m * 2^n)。
2:动态规划
先定义一些内容:定义两个字符串X,Y
Xi=<x1,x2.....xi> 表示字符串的 i 前缀
Yj = <y1,y2....yj> 表示字符串y的j前缀
用LCS(Xi,Yj) 表示字符串X,Y的最长公共子序列
如果:
- Xm = Yn(如果字符串X的第m位置上的字符等于字符串Y的第n个位置上的字符(下面类似,不再表述))
则LCS(Xm,Yn) = LCS(Xm-1,Yn-1)+Xm
- Xm != Yn
则LCS(Xm,Yn) = LCS(Xm-1,Yn) 或者LCS(Xm,Yn)=LCS(Xm,Yn-1)
但是为了追求最大的公共子串则可以这么定义:LCS(Xm,Yn) = max { LCS ( Xm-1 , Yn ) , LCS( Xm , Yn-1 ) }
所以综上两种情况,我们可以得出如下的推导公式:
最后的最长公共子序列 ,为了将问题变成数学问题,可以这么定义上面的过程。
- 利用一个二维数组表示每一部分LCS的长度 c[m][n]
- 用c[i][j] 记录字符串Xi和Yj的最长公共子序列长度。
因此可以得到下面的推论:
为了方便表示,我们可以将字符的从1开始。
下面是一个实例图
对于 X = ABCBDAB
Y = BDCABA
下面是具体的代码演示:
import java.util.Stack; /**
* 题目:最长公共子序列。(longest common subsequence)
* 比如字符串a = acdfg b =adfc 则其lcs 为 adf 。
* 思路:可以利用动态规划的思想。
*
* @author Xia
*
*/
public class StringLCS {
public String lsc(String s1,String s2){
int len1 = s1.length();
int len2 = s2.length();
//用一个二维数组表示,这里面为了方便表示将数组行、列都扩大一个(想一想原因,可以结合上面的模式图思考)
int[][] c = new int[len1 + 1][len2 + 1];
//为了配合上面的增加一列,字符串中也应该增加一个字符
s1 = ","+s1;
s2 = "?"+s2; //c中的第一行第一列都赋值为0
int i,j;
for (i = 0; i <= len1; i++) {
c[i][0] = 0;
} for (j = 0; j <= len2; j++) {
c[0][j] = 0;
}
//这里面开始遍历的时候必须从1开始
for ( i = 1; i <= len1; i++) {
for ( j = 1; j <= len2; j++) {
if (s1.charAt(i) == s2.charAt(j)) {
c[i][j] = c[i-1][j-1]+ 1;
}else {
c[i][j] = Math.max(c[i-1][j], c[i][j-1]);
}
}
}
//--------------两层for循环结束后即可得到最长公共子序列的长度 //--------------开始求解最长公共子序列------------------
//从求好的二维数组末端开始向前寻找,那么为了最后能够最长的输出子序列,需要定义一个stack
i = len1;
j = len2;
Stack<Character> s = new Stack<Character>();
while (i != 0 && j != 0) {
if (s1.charAt(i) == s2.charAt(j)) {
s.push(s1.charAt(i));
i--;
j--;
}else {
if (c[i][j-1] > c[i-1][j]) {
j--;
}else {
i--;
}
}
}
//-------------到这一步,已经求好了最长公共子序列并且存储在stack中
StringBuilder sb = new StringBuilder();
while (!s.isEmpty()) {
sb.append(s.pop());
}
return sb.toString();
} }
测试类:
public class Test {
public static void main(String[] args) {
StringLCS lcs = new StringLCS();
String s1 = "acdfg";
String s2 = "adcf";
String result = lcs.lsc(s1, s2);
System.out.println(result); //acf
}
}
总结:根据最后的结论,多运行几次我们可以看到,其实最长公共子序列是可以有多种情况的。
还会继续更新关于其他的字符串的操作算法演示。
算法练习——最长公共子序列的问题(LCS)的更多相关文章
- Java实现 蓝桥杯VIP 算法提高 最长公共子序列
算法提高 最长公共子序列 时间限制:1.0s 内存限制:256.0MB 问题描述 给定两个字符串,寻找这两个字串之间的最长公共子序列. 输入格式 输入两行,分别包含一个字符串,仅含有小写字母. 输出格 ...
- ACM/ICPC 之 最长公共子序列计数及其回溯算法(51Nod-1006(最长公共子序列))
这道题被51Nod定为基础题(这要求有点高啊),我感觉应该可以算作一级或者二级题目,主要原因不是动态规划的状态转移方程的问题,而是需要理解最后的回溯算法. 题目大意:找到两个字符串中最长的子序列,子序 ...
- 【算法】最长公共子序列(nlogn)
转载注明出处:http://blog.csdn.net/wdq347/article/details/9001005 (修正了一些错误,并自己重写了代码) 最长公共子序列(LCS)最常见的算法是时间复 ...
- 算法实践--最长公共子序列(Longest Common Subsquence)
什么是最长公共子序列 X=ACCG Y=CCAGCA 长度为1的公共子序列: {A} {C} {G} 长度为2的公共子序列:{AC} {CC} {CG} {AG} 长度为3的公共子序列:{ACG} 长 ...
- P2516 [HAOI2010]最长公共子序列 题解(LCS)
题目链接 最长公共子序列 解题思路 第一思路: 1.用\(length[i][j]\)表示\(a\)串的前\(i\)个字符与\(b\)串的前\(j\)个字符重叠的最长子串长度 2.用\(num[i][ ...
- 最长公共子序列问题(LCS)——Python实现
# 最长公共子序列问题 # 作用:求两个序列的最长公共子序列 # 输入:两个字符串数组:A和B # 输出:最长公共子序列的长度和序列 def LCS(A,B): print('输入字符串数组A', ...
- 最长公共子序列问题(LCS) 洛谷 P1439
题目:P1439 [模板]最长公共子序列 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 关于LCS问题,可以通过离散化转换为LIS问题,于是就可以使用STL二分的方法O(nlogn ...
- 《算法导论》读书笔记之动态规划—最长公共子序列 & 最长公共子串(LCS)
From:http://my.oschina.net/leejun2005/blog/117167 1.先科普下最长公共子序列 & 最长公共子串的区别: 找两个字符串的最长公共子串,这个子串要 ...
- 程序员的算法课(6)-最长公共子序列(LCS)
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/m0_37609579/article/de ...
随机推荐
- 第二十四天- 模块导入 import from xxx import xxx
# 模块:# 模块就是⼀个包含了python定义和声明的⽂件,⽂件名就是模块的名字加上.py后缀# 换句话说我们⽬前写的所有的py⽂件都可以看成是⼀个模块# 为何用模块:写大项目时,把相关的功能进⾏分 ...
- JavaWeb学习总结(七):通过Servlet生成验证码及其应用 (BufferedImage类)
一.BufferedImage类介绍 生成验证码图片主要用到了一个BufferedImage类,如下:
- 【vue】webpack插件svg-sprite-loader---实现自己的icon组件
引言:最近开始写vue的项目,借鉴了一下vue-element-admin源码,针对vue有一个关于icon图标的处理,最近也找了很多关于vue的icon处理的解决方案,大部分都是按照之前小程序的方式 ...
- Google zxing实现二维码扫描完美解决方案
最近因项目需求,需要在App中集成二维码扫描的功能.网上找了很多资料,最后决定使用Google的zxing来实现.实现的过程遇到了很多的坑,也是因为这些坑在网上没有具体的解决方案,今天就把我的实现过程 ...
- Android上实现视频录制
首先,我们肯定要用到摄像头,因此需要在Manifest文件中声明使用权限: <uses-permission android:name="android.permission.CAME ...
- 前端 css+js实现返回顶部功能
描述: 本文主要是讲,通过css+js实现网页中的[返回顶部]功能. 实现代码: HTML: <div> <button onclick="returnTop()" ...
- 关于jsp页面中时间显示问题
首先说明一下情况,在MySQL数据库中获取的时间显示在jsp页面中不是按指定格式显示,显示的是类似于这种--Tue Jun 18 00:00:00 CST 2013.而想要的仅仅是年月日而已. 对于这 ...
- 异度之刃 Xenoblade 后感
WII版重置的N3DS劣化版异度之刃终于通关了.在出色的自制系统的快乐NTR的帮助下,充分体验到了神作的剧情史诗感. 关于游戏的玩法系统,从现在来看8年前的游戏,缺点显而易见,特别是跑地图这回事,地图 ...
- windows 命令行报错:file(s) not in client view
今天在执行p4 sync命令时报错:File(s) not in client view,查找后发现其实是未连接上p4服务器.需要重新设置P4PORT=服务器地址 即可解决(参考链接:https:/ ...
- MySQL 、SQL MS Access、和 SQL Server 数据类型
MySQL 数据类型 在 MySQL 中,有三种主要的类型:Text(文本).Number(数字)和 Date/Time(日期/时间)类型. Text 类型: 数据类型 描述 CHAR(size) 保 ...