最长公共子序列问题
算法,最长公共子序列
最长公共子序列(LCS)问题(非连续子序列)的两种解法最长公共子序列也称作最长公共子串,英文缩写是LCS(Longest Common Subsequence)。
其定义是:一个序列S,如果分别是两个或多个已知序列的子序列,且是符合此条件的子序列中最长的,则称S为已知序列的最长公共子序列。
关于子序列的定义通常有两种方式,一种是对子序列没有连续的要求,其子序列的定义就是原序列中删除若干元素后得到的序列。
另一种是对子序列有连续的要求,其子序列的定义是原序列中连续出现的若干个元素组成的序列。
求解子序列是非连续的最长公共子序列问题是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。
本文将介绍对子序列没有连续性要求的情况下如何用计算机解决最长公共子序列问题,对子序列有连续性要求的情况下如何用计算机解决最长公共子序列问题将在后续的文章中介绍。
一、动态规划法(Dynamic Programming)最长公共子序列问题应该是属于多阶段决策问题中求最优解一类的问题,凡此类问题在编制计算机程序时应优先考虑动态规划法,如果不能用动态规划法,而且也找不到其它解决方法,还可以考虑穷举法。
对于这个问题,只要能找到描述最长公共子序列的最优子结构和最优解的堆叠方式,并且保证最优子结构中的每一次最优决策都满足“无后效性”,就可以考虑用动态规划法。
使用动态规划法的关键是对问题进行分解,按照一定的规律分解成子问题(分解后的子问题还可以再分解,这是个递归的过程),通过对子问题的定义找出最优子结构中最优决策序列(对于子问题就是最有决策序列的子序列)以及最优决策序列子序列的递推关系(当然还包括递推关系的边界值)。
如果一个给定序列的子序列是在该序列中删去若干元素后得到的序列,也就意味着子序列在原序列中的位置索引(下标)保持严格递增的顺序。
例如,序列S = <B,C,D,B>是序列K = <A,B,C,B,D,A,B>的一个子序列(非连续),序列S的元素在在K中的位置索引I = [2,3,5,7],I是一个严格递增序列。
[DataStructure]LCSs——最长公共子序列和最长公共子串
[DataStructure]LCSs——最长公共⼦序列和最长公共⼦串1. 什么是 LCSs? 什么是 LCSs? 好多博友看到这⼏个字母可能⽐较困惑,因为这是我⾃⼰对两个常见问题的统称,它们分别为最长公共⼦序列问题(Longest-Common-Subsequence)和最长公共⼦串(Longest-Common-Substring)问题。
这两个问题⾮常的相似,所以对不熟悉的同学来说,有时候很容易被混淆。
下⾯让我们去好好地理解⼀下两者的区别吧。
1.1 ⼦序列 vs ⼦串 ⼦序列是有序的,但不⼀定是连续,作⽤对象是序列。
例如:序列 X = <B, C, D, B> 是序列 Y = <A, B, C, B, D, A, B> 的⼦序列,对应的下标序列为 <2, 3, 5, 7>。
⼦串是有序且连续的,左右对象是字符串。
例如 a = abcd 是 c = aaabcdddd 的⼀个⼦串;但是 b = acdddd 就不是 c 的⼦串。
1.2 最长公共⼦序列 vs 最长公共⼦串 最长公共⼦序列和最长公共⼦串是常见的两种问题,虽然两者问题很相似,也均可以根据动态规划进⾏求解,但是两者的本质是不同的。
最长公共⼦序列问题是针对给出的两个序列,求两个序列最长的公共⼦序列。
最长公共⼦串问题是针对给出的两个字符串,求两个字符串最长的公共⼦串(有关字符串匹配相关算法可以转⾄博客《》)。
2. 动态规划⽅法求解LCSs 前⾯提到,动态规划⽅法均可以⽤到最长公共⼦序列和最长公共⼦串问题当中,在这⾥我们就不⼀⼀进⾏求解了。
我们以最长公共⼦序列为例,介绍⼀下如何利⽤动态规划的思想来解决 LCSs。
给定两个序列,找出在两个序列中同时出现的最长⼦序列的长度。
对于每⼀个序列⽽⾔,其均具有a m中⼦序列,因此采⽤暴⼒算法的时间复杂度是指数级的,这显然不是⼀种好的解决⽅案。
下⾯我们看⼀下,如何使⽤动态规划的思想来解决最⼤公共⼦序列问题。
最长公共子序列问题
2.3最长公共子序列问题和前面讲的有所区别,这个问题的不涉及走向。
很经典的动态规划问题。
例题16最长公共子序列(lcs.pas/c/cpp)【问题描述】一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
确切地说,若给定序列X= < x1, x2,…, xm>,则另一序列Z= < z1, z2,…, zk>是X的子序列是指存在一个严格递增的下标序列< i1, i2,…, ik>,使得对于所有j=1,2,…,k有Xij=Zj例如,序列Z=是序列X=的子序列,相应的递增下标序列为<2,3,5,7>。
给定两个序列X 和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y的公共子序列。
例如,若X= < A, B, C, B, D, A, B>和Y= < B, D, C, A, B, A>,则序列是X和Y的一个公共子序列,序列也是X和Y的一个公共子序列。
而且,后者是X和Y的一个最长公共子序列,因为X和Y没有长度大于4的公共子序列。
给定两个序列X= < x1, x2, …, xm>和Y= < y1, y2, … , yn>,要求找出X和Y的一个最长公共子序列。
【输入文件】输入文件共有两行,每行为一个由大写字母构成的长度不超过200的字符串,表示序列X和Y。
【输出文件】输出文件第一行为一个非负整数,表示所求得的最长公共子序列的长度,若不存在公共子序列,则输出文件仅有一行输出一个整数0,否则在输出文件的第二行输出所求得的最长公共子序列(也用一个大写字母组成的字符串表示。
【输入样例】ABCBDABBDCBA【输出样例】4BCBA【问题分析】这个问题也是相当经典的。
这个题目的阶段很不明显,所以初看这个题目没什么头绪,不像前面讲的有很明显的上一步,上一层之类的东西,只是两个字符串而且互相没什么关联。
但仔细分析发现还是有入手点的:既然说是动态规划,那我们首先要考虑的就是怎么划分子问题,一般对于前面讲到的街道问题和数塔问题涉及走向的,考虑子问题时当然是想上一步是什么?但这个问题没有涉及走向,也没有所谓的上一步,该怎么办呢?既然是求公共子序列,也就有第一个序列的第i个字符和第二个序列的第j个字符相等的情况。
最长公共子序列测试用例
最长公共子序列测试用例最长公共子序列(Longest Common Subsequence)是一种经典的问题,涉及到字符串处理和动态规划,具有广泛的应用场景。
在本文中,我们将详细探讨最长公共子序列问题,并给出一些有指导意义的测试用例。
首先,让我们先明确一下最长公共子序列的定义。
给定两个序列,我们需要找到它们最长的公共子序列,即能够从两个序列中分别取出若干元素,但相对顺序保持不变的最长子序列。
例如,对于序列"ABCD"和"ACDF",它们的最长公共子序列是"ACD"。
接下来,我们来考虑一些测试用例。
首先,我们可以选择两个完全相同的序列,这样最长公共子序列就是它们本身。
例如,对于序列"ABCD"和"ABCD",它们的最长公共子序列就是它们本身。
其次,我们可以选择两个没有公共子序列的序列。
例如,对于序列"ABCD"和"EFGH",它们之间没有任何相同的元素,因此最长公共子序列为空。
另外,我们还可以选择两个长度相同但内容不同的序列,这将涉及到如何处理不同元素的情况。
例如,对于序列"ABCD"和"DCBA",它们的最长公共子序列是"AD"。
我们需要验证算法是否能够正确处理元素的顺序。
此外,我们还需要考虑一个序列是另一个序列的子序列的情况。
例如,对于序列"ABC"和"ABCD",它们的最长公共子序列是"ABC",其中一个序列是另一个序列的子序列。
我们需要验证算法是否能够正确处理这种情况。
最后,我们可以选择两个长度不同但内容相同的序列,这将测试算法在处理不同长度序列时的表现。
例如,对于序列"ABCDE"和"BCD",它们的最长公共子序列是"BCD"。
最长公共子序列问题;
最长公共子序列问题;最长公共子序列(Longest Common Subsequence, LCS)问题是指找到多个字符串中最长的公共子序列。
公共子序列是指这些字符串在所有字符串中都以相同的顺序出现,但不要求连续。
例如,对于字符串"ABCD"和"ACDF",其最长公共子序列为"ACD"。
最长公共子序列问题可以通过动态规划来解决。
基本思路是使用一个二维数组dp,其中dp[i][j]表示字符串A的前i个字符和字符串B的前j个字符的最长公共子序列的长度。
首先,初始化dp[0][j]和dp[i][0]为0,表示空字符串与任何字符串的最长公共子序列长度为0。
然后,对于每个字符A[i]和B[j],如果A[i]等于B[j],则dp[i][j] = dp[i-1][j-1] + 1,表示在之前的最长公共子序列长度的基础上加1。
否则,dp[i][j] = max(dp[i-1][j], dp[i][j-1]),表示要么在字符串A的前i-1个字符和字符串B的前j个字符的最长公共子序列的基础上取得,要么在字符串A的前i个字符和字符串B的前j-1个字符的最长公共子序列的基础上取得。
最终,dp[m][n]即为所求,其中m和n分别为字符串A和字符串B的长度。
可以通过追踪dp数组来还原出最长公共子序列,具体方法是从dp[m][n]开始,如果A[i]等于B[j],则该字符是公共字符,将其加入结果序列,然后向左上方移动,即dp[i-1][j-1]。
如果dp[i][j]等于dp[i-1][j],则说明最长公共子序列在A中取得,向上移动,即dp[i-1][j];如果dp[i][j]等于dp[i][j-1],则说明最长公共子序列在B中取得,向左移动,即dp[i][j-1]。
重复上述过程,直到dp[i][j]为0。
最长公共子序列问题
1. 实验环境本实验采用java语言编写实现,环境:,编译器:eclipse2. 实验目的通过最长公共子序列问题,巩固并详细分析动态规划思想和解题步骤。
3. 设计思路最长公共子序列的定义为:设有两个序列S1[1..m]和S2[1..n],需要寻找它们之间的一个最长公共子序列。
例如,假定有两个序列:S1:I N T H E B E G I N N I N GS2:A L L T H I N G S A R E L O S T则S1和S2的一个最长公共子序列为THING。
又比如:S1:A B C B D A BS2:B D C A B A则它们的一个最长公共子序列为BCBA。
这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。
另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。
当然,如果要求子序列里面的元素必须连成一片也是可以的。
实际上,连成一片的版本比这里实现的更容易。
4. 过程我们可以通过蛮力策略解决这个问题,步骤如下:1. 检查S1[1..m]里面每一个子序列。
2. 看看其是否也是S2[1..n]里的子序列。
3. 在每一步记录当前找到的子序列里面最长的子序列。
这种方法的效率十分低下。
因此本实验采用动态规划的方法实现该算法。
利用动态规划寻找最长公共子序列步骤如下:1. 寻找最长公共子序列的长度。
2. 扩展寻找长度的算法来获取最长公共子序列。
策略:考虑序列S1和S2的前缀序列。
设c[i,j] = |LCS (S1[1..i],S2[1..j])|,则有c[m,n] = |LCS(S1,S2)|所以有c[ i – 1 , j – 1 ] + 1,如要S1[i] = S2[j]c[i,j] =max{ c [ i - 1,j ],c[ i ,j -1 ] },如果S1[i]≠S2[j]然后回溯输出最长公共子序列过程:5. 实现源代码package lcsimple;public class LCSImplem {断点调试及代码分析首先在main方法里定义两个字符串,如:对这两个字符串,使它们的第一个字符为空,即初始化之后的c[][]的第一行第一列,之所以要空出,是因为c[][]代表的是两个字符串数组多少个,0的意思就是某个字符串的长度为0。
动态规划经典——最长公共子序列问题(LCS)和最长公共子串问题
动态规划经典——最长公共⼦序列问题(LCS)和最长公共⼦串问题⼀.最长公共⼦序列问题(LCS问题)给定两个字符串A和B,长度分别为m和n,要求找出它们最长的公共⼦序列,并返回其长度。
例如: A = "Hel lo W o rld" B = "loo p"则A与B的最长公共⼦序列为 "loo",返回的长度为3。
此处只给出动态规划的解法:定义⼦问题dp[i][j]为字符串A的第⼀个字符到第 i 个字符串和字符串B 的第⼀个字符到第 j 个字符的最长公共⼦序列,如A为“app”,B为“apple”,dp[2][3]表⽰ “ap” 和 “app” 的最长公共字串。
注意到代码中 dp 的⼤⼩为 (n + 1) x (m + 1) ,这多出来的⼀⾏和⼀列是第 0 ⾏和第 0 列,初始化为 0,表⽰空字符串和另⼀字符串的⼦串的最长公共⼦序列,例如dp[0][3]表⽰ "" 和“app” 的最长公共⼦串。
当我们要求dp[i][j],我们要先判断A的第i个元素B的第j个元素是否相同即判断A[i - 1]和 B[j -1]是否相同,如果相同它就是dp[i-1][j-1]+ 1,相当于在两个字符串都去掉⼀个字符时的最长公共⼦序列再加 1;否则最长公共⼦序列取dp[i][j - 1] 和dp[i - 1][j]中⼤者。
所以整个问题的初始状态为:dp[i][0]=0,dp[0][j]=0相应的状态转移⽅程为:dp[i][j]=max{dp[i−1][j],dp[i][j−1]},A[i−1]!=B[j−1] dp[i−1][j−1]+1,A[i−1]==B[j−1]代码的实现如下:class LCS{public:int findLCS(string A, int n, string B, int m){if(n == 0 || m == 0)//特殊输⼊return 0;int dp[n + 1][m + 1];//定义状态数组for(int i = 0 ; i <= n; i++)//初始状态dp[i][0] = 0;for(int i = 0; i <= m; i++)dp[0][i] = 0;for(int i = 1; i <= n; i++)for(int j = 1; j<= m; j++){if(A[i - 1] == B[j - 1])//判断A的第i个字符和B的第j个字符是否相同dp[i][j] = dp[i -1][j - 1] + 1;elsedp[i][j] = max(dp[i - 1][j],dp[i][j - 1]);}return dp[n][m];//最终的返回结果就是dp[n][m]}};该算法的时间复杂度为O(n*m),空间复杂度为O(n*m)。
最长公共子序列问题
目录1 前言02 需求分析12.1 任务和要求12.2 运行环境12.3 开发工具13 分析和设计13.1 系统分析及设计思路13.2 主要数据结构及算法23.3 函数流程图24 具体代码实现35 课程设计总结135.1 程序运行结果或预期运行结果135.2 设计结论13参考文献14致谢141 前言若给定序列X={x1,x2,…,x m},则另一序列Z={z1,z2,…,z k},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y 的子序列时,称Z是序列X和Y的公共子序列。
请使用C语言编程,设计一个有效的算法解决下述问题:给定2个序列X={x1,x2,…,x m}和Y={y1,y2,…,y n},找出X和Y 的最长公共子序列。
2 需求分析2.1任务和要求使用C语言编程,设计一个有效的算法解决下述问题:给定2个序列X={x1,x2,…,x m}和Y={y1,y2,…,y n},找出X和Y的最长公共子序列。
2.2运行环境(1)WINDOWS2000/XP系统(2)Visual C++ 6.0编译环境或TC编译环境2.3开发工具C语言3 分析和设计3.1 系统分析及设计思路设序列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的最长公共子序列。
由此可见,2个序列的最长公共子序列包含了这2个序列的前缀的最长公共子序列。
Pascal最长公共子序列问题
考虑最长公共子序列问题如何分解成子问题,设A=“a0,a1,…, am-1”,B=“b0,b1,…,bm-1”,并Z=“z0,z1,…,zk-1” 为它们的最长公共子序列。不难证明有以下性质: (1) 如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0, z1,…,zk-2”是“a0,a1,…,am-2”和“b0,b1,…, bn-2”的一个最长公共子序列; (2) 如果am-1<>bn-1,则若zk-1<>am-1,蕴涵“z0, z1,…,zk-1”是“a0,a1,…,am-2”和“b0,b1,…, bn-1”的一个最长公共子序列; (3) 如果am-1<>bn-1,则若zk-1<>bn-1,蕴涵“z0, z1,…,zk-1”是“a0,a1,…,am-1”和“b0,b1,…, bn-2”的一个最长公共子序列。 这样,在找A和B的公共子序列时,如有am-1=bn-1,则进一步解 决一个子问题,找“a0,a1,…,am-2”和“b0,b1,…, bm-2”的一个最长公共子序列;如果am-1!=bn-1,则要解决两 个子问题,找出“a0,a1,…,am-2”和“b0,b1,…,bn1”的一个最长公共子序列和找出“a0,a1,…,am-1”和“b0, b1,…,bn-2”的一个最长公共子序列,再取两者中较长者作为 A和B的最长公共子序列。
begin assign(input,'lis.in'); reset(input); assign(output,'lis.out'); rewrite(output); readln(n); for i:=1 to n do maxn[i]:=30000; for i:=1 to n do read(num[i]); dp[1]:=1; maxn[1]:=num[1]; e:=1; for i:=2 to n do {动态规划过程} begin k:=find(num[i])+1; if k+1>dp[i] then dp[i]:=k+1; if k+1>e then e:=k+1; if num[i]<maxn[dp[i]] then maxn[dp[i]]:=num[i]; end;
最长公共子序列
最长公共子序列1 问题描述若给定序列X={x1,x2,…,x m},则另一序列Z={z1,z2,…,z k},是X的子序列是指存在一个严格递增下标序列{i1,i2,…,ik}使得对于所有j=1,2,…,k有:zj=xij。
例如,序列Z={B,C,D,B}是序列X={A,B,C,B,D,A,B}的子序列,相应的递增下标序列为{2,3,5,7}。
给定2个序列X和Y,当另一序列Z既是X的子序列又是Y的子序列时,称Z是序列X和Y 的公共子序列。
请使用C语言编程,设计一个有效的算法解决下述问题:给定2个序列X={x1,x2,…,x m}和Y={y1,y2,…,y n},找出X和Y的最长公共子序列。
2 问题分析、推导过程(最优子结构证明,最优值递归定义)1)动态规划算法事实上,最长公共子序列问题也有最优子结构性质。
记:Xi=﹤x1,⋯,xi﹥即X序列的前i个字符 (1≤i≤m)(前缀)Yj=﹤y1,⋯,yj﹥即Y序列的前j个字符 (1≤j≤n)(前缀)假定Z=﹤z1,⋯,zk﹥∈LCS(X , Y)。
若xm=yn(最后一个字符相同),则不难用反证法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有zk = xm = yn 且显然有Zk-1∈LCS(Xm-1 , Yn-1)即Z的前缀Zk-1是Xm-1与Yn-1的最长公共子序列。
此时,问题化归成求Xm-1与Yn-1的LCS (LCS(X , Y)的长度等于LCS(Xm-1 , Yn-1)的长度加1)。
若xm≠yn,则亦不难用反证法证明:要么Z∈LCS(Xm-1, Y),要么Z∈LCS(X , Yn-1)。
由于zk≠xm与zk≠yn其中至少有一个必成立,若zk≠xm则有Z∈LCS(Xm-1 , Y),类似的,若zk≠yn 则有Z∈LCS(X , Yn-1)。
此时,问题化归成求Xm-1与Y的LCS及X与Yn-1的LCS。
LCS(X , Y)的长度为:max{LCS(Xm-1 , Y)的长度, LCS(X , Yn-1)的长度}。
分支限界法典型例题
分支限界法典型例题分支限界法(Branch and Bound)是一种常见的算法分析技术,用于解决搜索问题和动态规划问题。
以下是一些分支限界法的典型例题:1. 最长公共子序列(LCS):求给定两个字符串的最长公共子序列。
可以使用分支限界法,首先找出两个字符串中的不同字符出现的次数,然后用哈希表存储这些计数器。
最后,遍历哈希表中的每个计数器,找到最大的计数器的值,即为最长公共子序列的长度。
2. 背包问题(Knapsack problem):给定一个背包,容量为64,有多个选项,每个选项的重量和容量不限。
求给定背包中可以放入的最大重量的背包物品。
可以使用分支限界法,首先列出所有可能背包容量的组合,然后用枚举法找出每个背包容量下可以放入的最大重量的物品,最后计算出可以放入的最大重量的物品数量。
3. 最短路径问题(Shortest Path problem):给定一个二维图,目标为找到从源点出发,到达所有目标点的路径。
可以使用分支限界法,首先找出图中的所有节点和它们之间的联系,然后用递归算法计算每个节点到源点的路径。
最后,通过剪枝,可以找到最短路径。
4. 最大子数组和问题(Maximum Subarray and Problem):给定一个数组,求出其中任意一个元素的最大值。
可以使用分支限界法,首先找出数组中的最小值和最大值,然后用递归算法计算每个元素的最大值。
最后,通过剪枝,可以找到最大子数组和问题。
5. 模拟退火问题(Simulated Annealing Problem):给定一个概率分布,求出在一定条件下,随机变量的取值分布。
可以使用分支限界法,首先找出概率分布中所有可能的取值,然后用模拟退火算法计算在这些取值中随机变量的取值分布。
最后,通过剪枝,可以找到最优解。
动态规划解最长公共子序列问题
动态规划解最长公共子序列问题动态规划主要针对最优化问题,它的决策是全面考虑不同的情况分别进行决策,,最后通过多阶段决策逐步找出问题的最终解.当各个阶段采取决策后,会不断决策出新的数据,直到找到最优解.每次决策依赖于当前状态,又随机引起状态的转移.一个决策序列就是在变化的状态中产生出来的,故有”动态”的含义.所以,这种多阶段最优化决策解决问题的过程称为动态规划.一问题的描述与分析字符序列的子序列是指从给定字符序列中随意地(不一定连续)去掉若干字符(可能一个也不去掉)后形成的字符序列..令给定的字符序列X=”x0,x1,x2,…xm-1”,序列Y=”y0,y1,…yk-1”是X的子序列,存在X的一个严格递增下标序列i=i0,i1,i2,…ik-1,使得对所有的j=0,1,2,…k-1,有xi=yi。
例如X=“ABCBDAB”,Y=“BCDB”是X的一个子序列。
给定两个序列A和B,称序列Z是A和B公共子序列,是指Z同是A和B的子序列。
求最长公共子序列。
若A的长度为m,B的长度为n,则A的子序列有2*m-1个,B的子序列有2*n-1个。
采用枚举法分别对A和B的所以子序列一一检查,最终求出最长公共子序列。
如此比较次数(2*2n)接近指数阶,当n较大时,算法太耗时,不可取。
所以要全面考虑不同的情况分别进行决策,,最后通过多阶段决策逐步找出问题的最终解.当各个阶段采取决策后,会不断决策出新的数据,直到找到最优解。
二、算法设计(或算法步骤)A=”a0,a1,a2,……am-1”,B=”b0,b1,b2,……bn-1”,且Z=”z0,z1,z2……zk-1”,为她们的最长公共子序列。
不难证明有一下结论:(1)如果am-1=bn-1,则zk-1=am-1=bn-1,且“z0,z1,z2,……zk-2”是“a0,a1,a2,……am-2”和“b0,b1,b2,……bn-2”的一个最长公共子序列;(2)如果am-1!=bn-1,则若zk-1!=am-1,则“z0,z1,z2,……zk-1”是“a0,a1,a2,……am-2”和”b0,b1,b2,……bn-1”的一个最长公共子序列。
2-最长公共子序列问题(无答案)
最长公共子序列问题(LCS)(生物信息学中常用算法)子序列的概念:设X=< x1, x2,┅, x m>,若有1≤i1< i2< ┅<i k≤m,使得Z=< z1, z2,┅, z k> = < x i1, x i2,┅, x ik>,则称Z是X的子序列,记为Z<X。
e.g. X=<A,B,C,B,D,A,B>, Z=<B,C,B,A>, 则有Z<X。
公共子序列的概念:设X,Y是两个序列,且有Z<X和Z<Y,则称Z是X和Y 的公共子序列。
最长公共子序列的概念:若Z<X,Z<Y,且不存在比Z更长的X和Y 的公共子序列,则称Z是X和Y 的最长公共子序列,记为Z∈LCS(X , Y)。
最长公共子序列往往不止一个。
e.g. X=<A,B,C,B,D,A,B>, Y=<B,D,C,A,B,A>, 则Z=<B,C,B,A>, Z’=<B,C,A,B>, Z’’=<B,D,A,B>均属于LCS(X , Y) ,即X,Y有3个LCS。
如何找出X和Y的一个最长公共子序列?Brute-force法:列出X的所有长度不超过n(即∣Y∣)的子序列,从长到短逐一进行检查,看其是否为Y的子序列,直到找到第一个最长公共子序列。
由于X共有2m个子序列,故此方法对较大的m没有实用价值。
是否能使用动态规划法?如何用?分析:记X i=﹤x1,…,x i﹥即X序列的前i个字符(1≤i≤m)(前缀)Y j=﹤y1,…,y j﹥即Y序列的前j个字符(1≤j≤n)(前缀)假定Z=﹤z1,…,z k﹥∈LCS(X , Y)。
若x m=y n(最后一个字符相同),则不难用反证法证明:该字符必是X与Y的任一最长公共子序列Z(设长度为k)的最后一个字符,即有z k = x m = y n且显然有Z k-1∈LCS(X m-1 , Y n-1) 即Z的前缀Z k-1是X m-1与Y n-1的最长公共子序列。
多序列最长公共子序列
针对多序列最长公共子序列问题,本文将研究以下几种算法:
1. 基于动态规划的算法
基于动态规划的算法是解决多序列最长公共子序列问题的经典方法。该方法通过构建一个 二维矩阵,记录每个位置上所有序列的最长公共子序列长度。然后,通过动态规划的方 法,自底向上地计算出多序列最长公共子序列的长度。
针对多序列最长公共子序列问题,目前已有许多算法被提出。其中,最著名的算法是 Knuth-Morris-Pratt(KMP)算法。KMP 算法是一种高效的字符串匹配算法,可以在 O(n) 的时间复杂度内完成字符串匹配。在多序列最长公共子序列问题中,KMP 算法可以被用 于加速子序列比对,从而提高算法的性能。然而,KMP 算法仅适用于较小的序列集合, 对于大规模序列集合,其性能并不理想。
通过实验证明,本文提出的算法具有较高的性能。在处理大规模序列集合时,算法能够在
较短的时间内得到正确的结果。此外,算法还具有较好的可扩展性,可以方便地应用于不 同规模的序列集合。
总结所述,本文针对多序列最长公共子序列问题进行了研究,并提出了一种有效的解决方 法。通过实验证明,该方法具有较高的性能和可扩展性,为多序列比对提供了一种有效的 工具。在未来的研究中,我们将进一步优化算法,并探索多序列最长公共子序列问题在更 多应用领域中的可能性。
【算法】 针对 MS-LCS 问题,目前已经提出了多种算法。其中,最著名的算法是动态规划算法。该算法 的基本思想是将多个序列两两比对,求出它们之间的 LCS,然后找出多个 LCS 中的最长序 列。该算法的时间复杂度为 O(nm^2),其中 n 是序列的数量,m 是序列的长度。由于该算法 的时间复杂度较高,因此在处理大规模序列数据时效率较低。为了解决这个问题,研究人员 提出了许多改进算法,如基于贪心策略的算法、基于分治思想的算法、基于动态规划的算法 等。这些算法的时间复杂度都比动态规划算法低,但在某些情况下,它们的准确性较低。
穷举法求解最长公共子序列
穷举法求解最长公共子序列啥是最长公共子序列呢?简单来说,就是在两个序列中找到一个共同的部分,而且这个部分的顺序不能乱。
想象一下,你跟小伙伴一块玩拼图,虽然每块拼图都不一样,但拼出来的图案得跟朋友那一块拼出来的图案一模一样,这可不是件容易的事儿。
说白了,就是要在一堆字符里找到那些相同的,而且顺序得对,真是个考脑筋的活儿!咱们先来想象一个场景,假设你有两个字符串,一个是“abcde”,另一个是“ace”。
从这两个字符串里,咱们要找出最长的公共子序列。
嘿,这个时候就像是在找宝藏一样,得一个个地去翻找。
你会发现,“a”、“c”、“e”都在这两个字符串里。
哇,这可真是个小惊喜,找到了!但要注意哦,它们的顺序不能变。
所以,最长公共子序列就是“ace”了。
这样一想,是不是感觉有点意思呢?好啦,现在咱们来谈谈穷举法。
听起来高大上,其实就是一个个试,试到你觉得“哎呀,我真是个天才”才行。
咱们得列出所有可能的子序列。
这可不是随便说说,你得有耐心。
比如说,从“abcde”中,咱们能列出“a”、“b”、“c”、“d”、“e”,还有“ab”、“ac”、“ad”,甚至“abc”、“abd”,直到“abcde”都得试试,直到没什么好试的为止。
听上去是不是有点让人心累,但一想到最后的结果,心里就乐开了花。
继续深入想想,穷举法可真是个老办法,但就是简单有效。
想想就像家里大扫除,把所有角落都翻遍,终于找到那个丢失已久的遥控器。
每个可能的组合都得看一遍,有些看起来毫无关系的组合,搞不好就能是答案呢!所以,穷举法就是个“捡漏”的过程,得慢慢来,着急可没用。
就像那句老话说得好,磨刀不误砍柴工,先找出所有的子序列,才能确定哪个是最长的。
说到这里,可能有人会问,这样做是不是太慢了?当然了,穷举法的时间复杂度就像在爬一座大山,越往上走越累。
为了找到答案,你可能得经历无数次的“失败”,但是一旦找到了,成就感简直爆棚。
就像考试前那种紧张,最后交卷时的轻松感,啊,真是太棒了。
最长公共子序列问题(最新)
算法作业:LCS 问 题作业要求:设计一个算法求出两个序列的所有LCS ,分析最坏情况,用“会计方法”证明利用b[i][j]求出所有LCS 的算法在最坏情况下时间复杂度为)(m m n C O +1、 算法思路:根据最长公共子序列问题的性质,即经过分解后的子问题具有高度重复性,并且具有最优子结构性质,采用动态规划法求解问题。
设X={x 1, x 2, … , x n }, Y={y 1, y 2, … , y m }, 首先引入二维数组C[i][j]记录X i 和Y j 的LCS 的长度,定义C[i][j]如下:{j i jy i 且x ,i,j ]][j C[i jy i x j i j i C j i C j i C 00001110,]},1][[],][1[max{]][[===>+--≠>--=或,且为了构造出LCS ,还需要使用一个二维数组b[m][n],b[i][j]记录C[i][j]是通过哪个子问题的值求得的,以决定搜索的方向,欲求出所有的LCS ,定义数组b 如下: 设1-对角线方向;2-向上;3-向左;4-向上或向左 若X[i]=Y[j],b[i][j] = 1,若C[i-1][j]<i][j-1], 则b[i][j] = 2, 若C[i-1][j]>[i][j-1], 则b[i][j] = 3, 若C[i-1][j]=[i][j-1], 则b[i][j] = 4,根据以上辅助数组C 和b 的定义,算法首先需要求出这两个数组, C[m][n]中记录的最长公共子序列的长度,b 中记录了查找子序列元素的搜索方向。
利用C 和b 的信息,Find_All_LCS 可以采用回溯法求出所有的LCS 。
基本思路如下:使用一个辅助数组记录每次调用Find_All_LCS 得到的LCS 中的元素,每次递归调用一次Find_All_LCS ,进入一个新的执行层,首先要判断当前处理的两个子序列长度是否大于等于0 ,若不满足,则该层的递归结束,返回上一层;然后再判断当前得到的子序列是否等于数组C 中求出的最长公共子序列长度,若等于,则说明算法执行到此已经得到一个LCS ,按序输出;若不等于,此时根据数组b 中记录的搜索方向继续搜索,特别要说明的是,当b[i][j]=4时,即要向上或向左,需要对这两个方向分别调用Find_All_LCS ,保证沿着这两个方向上LCS 元素不被漏掉,都可以搜索到;若b[i][j]=1,即沿对角线方向搜索前进时,此时元素X[i]为LCS 中的元素,存放至辅助数组中去,同时将当前已经求得的LCS 长度增1,当递归调用Find_All_LCS 从b[i][j]=1处时,需要回溯一步,搜索其它路径上可能为LCS 中的元素。
算法系列之六:最长公共子序列(LCS)问题(连续子序列)的三种解法
算法系列之六:最长公共子序列(LCS)问题(连续子序列)的三种解法最长公共子序列(LCS)问题有两种方式定义子序列,一种是子序列不要求不连续,一种是子序列必须连续。
上一章介绍了用两种算法解决子序列不要求连续的最终公共子序列问题,本章将介绍要求子序列必须是连续的情况下如何用算法解决最长公共子序列问题。
仍以上一章的两个字符串“abcdea”和“aebcda”为例,如果子序列不要求连续,其最长公共子序列为“abcda”,如果子序列要求是连续,则其最长公共子序列应为“bcd”。
在这种情况下,有可能两个字符串出现多个长度相同的公共子串,比如“askdfiryetd”和“trkdffirey”两个字符串就存在两个长度为3的公共子串,分别是“kdf”和“fir”,因此问题的性质发生了变化,需要找出两个字符串所有可能存在公共子串的情况,然后取最长的一个,如果有多个最长的公共子串,只取其中一个即可。
字符串“abcdea”和“aebcda”如果都以最左端的a字符对齐,则能够匹配的最长公共子串就是“a”。
但是如果用第二个字符串的e字符对齐第一个字符串的a 字符,则能够匹配的最长公共子串就是“bcd”。
可见,从两个字符串的不同位置开始对齐匹配,可以得到不同的结果,因此,本文采用的算法就是穷举两个字符串所有可能的对齐方式,对每种对齐方式进行字符的逐个匹配,找出最长的匹配子串。
一、递归方法首先看看递归方法。
递归的方法比较简单,就是比较两个字符串的首字符是否相等,如果相等则将其添加到已知的公共子串结尾,然后对两个字符串去掉首字符后剩下的子串继续递归匹配。
如果两个字符串的首字符不相等,则用三种对齐策略分别计算可能的最长公共子串,然后取最长的一个与当前已知的最长公共子串比较,如果比当前已知的最长公共子串长就用计算出的最长公共子串代替当前已知的最长公共子串。
第一种策略是将第一个字符串的首字符删除,将剩下的子串与第二个字符串继续匹配;第二种策略是将第二个字符串的首字符删除,将剩下的子串与第一个字符串继续匹配;第三种策略是将两个字符串的首字符都删除,然后继续匹配两个字符串剩下的子串。
最长公共子序列
0-1背包问题
问题描述
0-1背包问题可描述为:n个物品和1个背包。对物品i,其价值为
vi,重量为wi,背包的容量为W。如何选取物品装入背包,使背 包中所装入的物品的总价值最大? n 约束条件: (4-7) wi xi W i=1 x {0,1},(1 i n) i 目标函数: (4-8) n
B
D
C
A
B
A
0 0 0 0 0 0 0 0
A B C B D A B
0 0 1 1 1 1 1 1
0 0 1 1 1 2 2 2
0 0 1 2 2 2 2 2
0 1ቤተ መጻሕፍቲ ባይዱ1 2 2 2 3 3
0 1 2 2 3 3 3 4
0 1 2 2 3 3 4 4
从i=7,j=6处向前递推 ,找到X和Y的最长公共子序列为{B,C,B,A}
最长公共子序列问题
基本概念 (1)子序列
给定序列 X={x1, x2, …, xn}、Z={z1, z2, …, zk},若 Z是X的子序列,当且仅当存在一个严格递增的下 标序列 {i1, i2, …, ik},对j∈{1, 2, …, k}有zj=x。 (2)公共子序列 给定序列X和Y,序列Z是X的子序列,也是Y的子序 列,则称Z是X和Y的公共子序列。 (3)最长公共子序列 包含元素最多的公共子序列即为最长公共子序列。
实例构造
【例4-6】给定序列X={A, B, C, B, D, A, B}和Y={B, D, C, A, B, A},求
它们的最长公共子序列。
(1)m=7,n=6,将停止条件填入数组c中,即
c[i][0]=0,c[0][j]=0,其中0≤i≤m,0≤j≤n。 (2)当i=1时,X1={A},最后一个字符为A;Yj的 规模从1逐步放大到6,其最后一个字符分别为B、 D、C、A、B、A; 依此类推,直到i=7。
最长公共子序列
一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
最长公共子序列问题是给定两个序列X={x1,x2...xm}和Y={y1,y2...yn},找出X和Y的最长公共子序列,用动态规划算法可有效的解些问题。
最长公共子序列的结构:设X = { x1 , ... , xm },Y = { y1 , ... , yn }及它们的最长子序列Z = { z1 , ... , zk }则1、若 xm = yn ,则 zk = xm = yn,且Z[k-1] 是 X[m-1] 和 Y[n-1] 的最长公共子序列2、若 xm != yn ,且 zk != xm , 则 Z 是 X[m-1] 和 Y 的最长公共子序列3、若 xm != yn , 且 zk != yn , 则 Z 是 Y[n-1] 和 X 的最长公共子序列子问题的递归结构:当 i = 0 , j = 0 时 , c[i][j] = 0当 i , j > 0 ; xi = yi 时 , c[i][j] = c[i-1][j-1] + 1当 i , j > 0 ; xi != yi 时 , c[i][j] = max { c[i][j-1] , c[i-1][j] }由以上分析,先计算最优值,再构造最长公共子序列,C++源程序如下:#include <stdio.h>#include <string.h>#include"iostream"using namespace std;int length=0; //记录最长公共序列长度//计算最优值void lcs(string x,string y,int **b){int i,j;//获取字符串的长度int m = x.size();int n = y.size();//创建动太二维数组int **c;c = new int*[m+1];for(int i = 0;i < m+1;i++)c[i] = new int[n+1];//初始化数组for (i=1;i<=m;i++) c[i][0] = 0;for (i=1;i<=n;i++) c[0][i] = 0;c[0][0] = 0;//遍历记录最优值,并将标识存在数组b中for (i=1;i<=m;i++)for (j=1;j<=n;j++){if (x[i-1] == y[j-1]){ //xm = yn ,则 zk = xm = yn,且Z[k-1] 是 X[m-1] 和 Y[n-1] 的最长公共子序列c[i][j] = c[i-1][j-1] + 1;b[i][j] = 1;}else if (c[i-1][j] > c[i][j-1]){ //xm != yn ,且 zk != xm , 则 Z 是 X[m-1] 和 Y 的最长公共子序列c[i][j] = c[i-1][j];b[i][j] = 2;}else{ //xm != yn , 且 zk != yn , 则 Z 是 Y[n-1] 和 X 的最长公共子序列c[i][j] = c[i][j-1];b[i][j] = 3;}}//释放空间for(int i = 0;i < m+1;i++)delete c[i];delete c;}//构造最长公共子序列void show(int i,int j,string x,int **b){//递归中止条件if (i==0||j==0)return ;//从b[m][n]开始,用递归依其值在数组b中搜索if (b[i][j]==1){ //xi和yj的最长公共子序列是由x(i-1)和y(j-1)的最长公共子序列在尾部加上xi所得到的子序列show(i-1,j-1,x,b);length++;cout << x[i-1];}else if (b[i][j]==2){ //xi和yi的最长公共子序列与x(i-1)和yj的最长公共子序列相同show(i-1,j,x,b);}else{ //xi和yi的最长公共子序列与xi和y(j-1)的最长公共子序列相同show(i,j-1,x,b);}}int main(){string x;string y;int **b;cout << "输入第一个序列";cin >> x;cout << "输入第二个序列";cin >> y;int m = x.size();int n = y.size();//创建二维动态数组b = new int*[m+1];for(int i = 0;i < m+1;i++)b[i] = new int[n+1];//求解最优值lcs(x,y,b);//构造序列并打印cout << "最长公共序列:";show(m,n,x,b);cout << "\n长度:" << length << endl;//释放空间for(int i = 0;i < m+1;i++)delete b[i];delete b;system("pause");return 0;}。
最长公共子序列问题
实验三最长公共子序列问题1. 实验环境本实验采用java语言编写实现,环境:,编译器:eclipse2. 实验目的通过最长公共子序列问题,巩固并详细分析动态规划思想和解题步骤。
3. 设计思路最长公共子序列的定义为:设有两个序列S1[1..m]和S2[1..n],需要寻找它们之间的一个最长公共子序列。
例如,假定有两个序列:S1:I N T H E B E G I N N I N GS2:A L L T H I N G S A R E L O S T则S1和S2的一个最长公共子序列为THING。
又比如:S1:A B C B D A BS2:B D C A B A则它们的一个最长公共子序列为BCBA。
这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。
另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。
当然,如果要求子序列里面的元素必须连成一片也是可以的。
实际上,连成一片的版本比这里实现的更容易。
4. 过程我们可以通过蛮力策略解决这个问题,步骤如下:1. 检查S1[1..m]里面每一个子序列。
2. 看看其是否也是S2[1..n]里的子序列。
3. 在每一步记录当前找到的子序列里面最长的子序列。
这种方法的效率十分低下。
因此本实验采用动态规划的方法实现该算法。
利用动态规划寻找最长公共子序列步骤如下:1. 寻找最长公共子序列的长度。
2. 扩展寻找长度的算法来获取最长公共子序列。
策略:考虑序列S1和S2的前缀序列。
设c[i,j] = |LCS (S1[1..i],S2[1..j])|,则有c[m,n] = |LCS(S1,S2)|所以有c[ i – 1 ,j – 1 ] + 1,如要S1[i] = S2[j]c[i,j] =max{ c [ i - 1,j ],c[ i ,j -1 ] },如果S1[i]≠S2[j]然后回溯输出最长公共子序列过程:5. 实现源代码package lcsimple;public class LCSImplem {断点调试及代码分析首先在main方法里定义两个字符串,如:对这两个字符串,使它们的第一个字符为空,即初始化之后的c[][]的第一行第一列,之所以要空出,是因为c[][]代表的是两个字符串数组多少个,0的意思就是某个字符串的长度为0。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
实验三最长公共子序列问题1. 实验环境本实验采用java 语言编写实现,环境:,编译器:eclipse2. 实验目的通过最长公共子序列问题,巩固并详细分析动态规划思想和解题步骤。
最长公共子序列的定义为:设有两个序列S i[1..m]和84仁n],需要寻找它们之间的一个最长公共子序列。
例如,假定有两个序列:81:I N T H E B E G I N N I N G82:A L L T H I N G 8 A R E L O 8 T则8i和S的一个最长公共子序列为THING又比如:81:A B C B D A B82:B D C A B A则它们的一个最长公共子序列为BCBA。
这里需要注意的是,一个子序列不一定必须是连续的,即中间可被其他字符分开,单它们的顺序必须是正确的。
另外,最长公共子序列不一定只有一个,而我们需要寻找的是其中一个。
当然,如果要求子序列里面的元素必须连成一片也是可以的。
实 际上,连成一片的版本比这里实现的更容易。
4.过程我们可以通过蛮力策略解决这个问题,步骤如下:1. 检查S1[1..m]里面每一个子序列。
2. 看看其是否也是S2[1..n]里的子序列。
3. 在每一步记录当前找到的子序列里面最长的子序列。
这种方法的效率十分低下。
因此本实验采用动态规划的方法实现 该算法。
利用动态规划寻找最长公共子序列步骤如下:1.寻找最长公共子序列的长度。
2.扩展寻找长度的算法来获取最长公共子序列。
策略:考虑序列S1和S2的前缀序列。
设 c[i ,j] = |LCS (S1[1..i],S2[1..j]),则有 c[m , n] = |LCS(S1S2)|所以有c[i ,j]=max{ c [ i - 1, j ], c[ i , j -1 ] },c[ i -1 , j -1 ] + 1,如要 S1[i] = S2[j]如果 S1[i]工 S2[j]然后回溯输出最长公共子序列过程:0 2 3 4 5 65.实现源代码p ackage Icsi mple; public classLCSImplem {断点调试及代码分析首先在main 方法里定义两个字符串,如: string strl = '*ABCBDAB*';String stu2 =CABA ";对这两个字符串,使它们的第一个字符为空,即初始化之后的c[][] 的第一行第一列,之所以要空出,是因为c[][]代表的是两个字符串数 组多少个,0的意思就是某个字符串的长度为 0。
然后将这两个字符 串分割为char 型数组:A BD叫〃 C A B 4Stri = E » 十 stri;str2 三+ str2;Gha.r [] fitringArrl = stri . toC :harArra.y (J ; char [] stringArr2 = str2.toCharArray (};接下来就调用getLength 方法计算出决定搜索方向的数组,传到该 方法的两个数组参数stringArrI 和stringArr2的值可以看到Value (iid=16}然后定义两个二维数组b[][],c[][],大小为*,用于接受结果矩阵。
int [ ] [ ] b = new inh [stringArrl . length) [stringArrl2 .length); int [ ] [ ] c = new inh [striiigAcr 1 . length][stringArrl2.length;;上——I — — J-— *1. J - ■ ---- --- — — -n ---------1 ~1 _ ------- 1. 1_ - -L ■■ b r接着遍历每一个stringArrI 的值,与stringArr2的每一个值做比较: foE (int i=l ; i<£tringAi;rl , l&ngtti; i++】{ for (Int j =1;j<st:riiigArrl2 . length; j ++} { f r n -■ r ■ T 叶・ I —I缀序列为后面的匹配计算使用,将当前值赋值为1, b[i][j]用于保存匹配结果记为1:N'ameV i'llAA ▲ A A A A tC On]罔t3J[■4JIV O stripgArrl?&A e cB D A G(irJ=171[C O t1] 【可 [3]GDCA BA循环内的第一层判断,就是当当前字符匹配的时候, c[i][j]最为前=吕2【j]的情说if [ stzingArrl[i] = string 貝rr12[j ]){C[i] [j] = G[i-i] [j-1] + 1; b[i] [j] = 1;把下面的两个判断作为第二层判断,即当当前字符不匹配的时候对c[i][j]做计算,c[i][j]就是该值在矩阵中上面一个数和左边一个数中 较大的值:."■51[丄]¥£2(泊的情况else if (G[i=l][j] >二 c [il [ j 一1]〕{ Ci] [j] = c[i-lj [j];b fi] tjI = 0 ;else {[j] = c[i] [j] = -1;这些判断就是对该矩阵值的计算,c 矩阵:但是这个方法返回的是矩阵,矩阵在当前位置在字符匹配时 的值为1,不匹配时,就对c 矩阵做出比较,该值在矩阵中左边的数 值大于上边的数值时,b 矩阵在当前位置在字符匹配时的值为 0,反tiA lCI£B2 3 4 5 6丹 B h CB 4之记为-1。
因此,计算返回b 矩阵,输出b 矩阵for(int i = 0 ; i < b -length ; i++}{for(int j = J ; j < b [i]- length ; j++)t System, out.print ( (b [i] [ j ] ) + " ;System-out .printIn();得到:Display [Y :r, stringArr 1. length-l , strirLqArr2.1昌ngth — 1);/归耳瘁d 弘用蟄Hprlvats stitic void Displav (int f ] fl b, char [1 strinqArr 1, int Int j )[ if (i == 0 I I J = 0)ire turn;±f (b[i3 [j] = 1) 4Display (b, stringFir E 1, i-l, ; -1 HSystem, out.print (?':z.ringArrL [i J + " "];吐j" i f (b [ i J [ J ] = 0) {PiffpJi strir.:iAr rl, i-i, i ) jelse if (b[i 1(j ] = -1> f当当前值为1时,说明字符匹配成功,再对左上方的值进行比较;当当前值为0时,说明左边的值大于上边的值,采用递归法,再对上 边的值进行比较;当当前值为-1时,对左边的值进行比较。
下面是对b 的迭代:0 0 0 0 0 0 0 0 0 1 0 1 0 0 1 0 0 -1 0' 0 1 0 0'0 0£-丄 丄0 0 0 0-1 Q 0 1 00 -11 011—丄 0 -1 0 1 0 最后就是对结果的输出,b 矩阵调用Dis play 方法:re turriFSystem . out rprintln (i+ '*==>* + j ); If (btij (j] = 1} {nJspJavtb, BrrzLnqAxrL, i —1, i —1); I 二二 Prrp(Mi*K Sprvw Dpt” Sourr* F 、plo 仲f 匕.^nrppstc 曰 Comfol*term ir diedLCSImpIcru [Java AppI icjtkj rtl D;\j Jk_1 ,fl^jdk_13\bin\ijvj-^VrCAc (2017^12^5 E E==J>€ b==>i 4==>i 3==>^3==>a| 2==>2 2=61这个方法,就是对下面矩阵方向的计算:O'-I丄最后输出判断中匹配上的结果。
片ABBDAH$1 R D C A B A3Ssa-1一丄[}7. 算法分析调用(m *由于每次调用至少向上或向左(或向上向左同时)移动一步,故 最多n)次就会遇到i 二0或j = 0的情况,此时开始返回。
返回时与递归调用时方向相反,步数相同,故算法时间复杂度为0(m *8. 实验结果在main 方法中输入的字符串为:-LPV7丄"U wd XX 1 丄 ■七String strl =String sZr2 = "BDCABA "; 所以得到结果:crerminated ; BC E A改变输入的字符串测试:HUJJ 亠亠 J n Jd V ■亠Vmn 丄 J,二 \ 7 XL JString strl = "ABCBDABEFEV'"; String str2 = BDCABAEFTcf*;£2 Markers D Properties 鼎 Servers 理 Data Source Eicplorer ib Snippe吒terminatedA LCSlmplem (Jdva Appikationj D;^ d k_1,8\jdk_1 .fl\b in\jdvaw.exeBC E A E F结果准确,实验结束。
9. 实验总结对最长公共子序列的求解,实际上是对动态规划思想的学习,这 个实验实现的算法比前两个实验实现的算法难度又有所提升, 对字符串进行反复递归时容易出错, 所以只能先对简单的字符串计算进行测rH50 51试。
个人认为,动态规划思想中难的部分就是突出在反复的循环/ 递归,对循环参数的取值往往让人伤神,需要十分谨慎小心,并反复的测验才能确保算法的正确性。