最长公共子序列

合集下载

算法,最长公共子序列

算法,最长公共子序列

最长公共子序列(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是一个严格递增序列。

最长公共子序列的最优值和最优解

最长公共子序列的最优值和最优解

最长公共子序列的最优值和最优解
最长公共子序列问题是求解两个序列中最长的相同子序列的问题。

假设两个序列分别为A和B,其长度分别为m和n。

则最长公共子序列的最优值可以用一个m*n的矩阵c来表示。

矩阵c的第i行第j列表示序列A的前i个元素与序列B的前j个元素的最长公共子序列的长度。

为了求解矩阵c,可以采用动态规划的方法。

具体实现方法如下:
1. 定义一个m*n的矩阵c和一个长度为m的数组b。

2. 通过循环,初始化矩阵c和数组b,使其元素值均为0。

3. 使用两个循环,遍历序列A和B的每个元素,如果元素相同,则将矩阵c的对应位置赋值为左上角元素值加1,并将数组b的对应位置赋值为1;否则将矩阵c的对应位置赋值为左侧和上方元素的较大值。

4. 遍历完序列A和B后,矩阵c的最后一个元素即为两个序列的最长公共子序列的长度。

5. 通过倒序遍历数组b,将序列A中对应元素添加到结果序列中,直至遍历完所有元素。

最终,得到的结果序列即为最长公共子序列的最优解。

在实际应用中,最长公共子序列问题有着广泛的应用,如字符串匹配、生物信息学和版本控制等方面。

最长公共子序列

最长公共子序列

最长公共子序列GE GROUP system office room 【GEIHUA16H-GEIHUA GEIHUA8Q8-动态规划一、问题描述用动态规划法求两个字符串A=‘xzyzzyx’和B=‘zxyyzxz’的最长公共子序列二、算法分析(1)、若xm=yn,则zk=xm=yn,且Zk-1是Xm-1和Yn-1的最长公共自序列;(2)、若xm≠yn,且zk≠xm,则Zk是Xm-1和Yn的最长公共自序列;(3)、若xm≠yn,且zk≠yn,则Zk是Xm和Yn-1的最长公共自序列;设L(m,n)表示序列X={x1,x2,…,xm}和Y={y1,y2,…,yn}的最长公共子序列的长度L表示已经决策的长度S表示每个决策的状态L(0,0)=L(0,j)=0 1≤i≤m, 1≤j≤nL(i-1,j-1)+1 xi=yi,i≥1,j≥1 L(i,j)=max{L(i,j-1),(L(i-1,j)} xi≠yi,i≥1,j≥1 1 xi=yiS(i,j)= 2 xi≠yi 且L(i,j-1)≥L(i-1,j)3 xi≠yi 且L(i,j-1)< L(i-1,j)长度矩阵L三、源代码#include <iostream>#include <string>using namespace std;int main(){string str1 = "xzyzzyx";string str2 = "zxyyzxz";int x_len = str1.length();int y_len = str2.length();int arr[50][50] ={{0,0}};int i = 0;int j = 0;for(i = 1; i <= x_len; i++){for(j = 1; j <= y_len; j++){if(str1[i - 1] == str2[j - 1]){arr[i][j] = arr[i - 1][j - 1] + 1;}else if(arr[i][j - 1] >= arr[i - 1][j]) arr[i][j] = arr[i][j - 1];elsearr[i][j] = arr[i -1][j];}}for(i = 0 ; i <= x_len; i++){for( j = 0; j <= y_len; j++){cout << arr[i][j] << " ";}cout << endl;}for(i = x_len, j = y_len; i >= 1 && j >= 1;) {if(str1[i - 1] == str2[j - 1]){cout << str1[i - 1] << " ";i--;j--;}else if(arr[i][j -1] > arr[i - 1][j]) j--;elsei--;}cout << endl;return 0;}。

最长公共子序列问题;

最长公共子序列问题;

最长公共子序列问题;最长公共子序列(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。

数据结构与算法题解:最长公共子序列和最长公共子串

数据结构与算法题解:最长公共子序列和最长公共子串
公共子子序列列数目目,那么接下来试试寻找其状态转移方方程。 从实际例例子子ABCD和EDCA出发,首首先初始化f的⻓长度为字符串串⻓长度加1,那么有
f [0][0] = 0, f [0][∗] = 0, f [∗][0] = 0,最后应该返回f [lenA][lenB]. 即 f 中索引与字符串串索引
ource, target)); }
}
二二、最⻓长公共子子串串
2.1 简单考虑
可以使用用两根指针索引分别指向两个字符串串的当前遍历位置,若遇到相等的字符时则同时向后移 动一一位。
public class Demo { public static int longestCommonSubstring(String A, String B) { if (A == null || A.length() == 0) return 0; if (B == null || B.length() == 0) return 0; int lenA = A.length(); int lenB = B.length(); int lcs = 0, lcs_temp = 0; for (int i = 0; i < lenA; ++i) { for (int j = 0; j < lenB; ++j) { lcs_temp = 0; while ((i + lcs_temp < lenA) && (j + lcs_temp < lenB) && (A.charAt(i + lcs_temp) == B.charAt(j + lcs_temp))) { ++lcs_temp; }

动态规划经典——最长公共子序列问题(LCS)和最长公共子串问题

动态规划经典——最长公共子序列问题(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)。

最长公共子序列

最长公共子序列

最长公共子序列
最长公共子序列(longest common subsequence,简称LCS)是在一系列序列中找到最长
公共子序列的算法,这是一种计算机科学中重要的算法,因为它可以用于文本处理、图像处理和生物信息学中的序列比较,并给定的两个序列的编辑距离。

关于LCS算法的历史,称为最早的提出者是Muntz在1971年提出的,但它后来也被Hirschberg和哈利时用来
计算机科学领域。

LCS算法是一种动态规划方法,它的关键在于它需要从底部开始着手,然后一步步的递推到上面,而不是传统的栈方式,只有从上面开始而不会有正确的结果,同时它具有极高的计算效率。

通过动态规划,我们可以用二维表dp[i] [j]来记录字符串X[0]…X[i] 与Y[0]…Y[j] 的LCS,这是该方法的最重要的步骤,每更新一次状态表dp,就可以获得一个新的解。

此外,我们可以使用空间换时间的思想来优化我们的LCS算法,通常有单行存储和单列存储两种方式,尽管这也大大降低了内存的占用,但在计算量的增加的情况下,这种方式也不是很实用。

最长公共子序列算法已经广泛应用在计算机科学,生物信息和图像处理上,它使得在序列比较或文本处理中的传统办法变得简单,更加可靠。

这种算法有着极高的计算效率,可以加快运算的速度,并使用尽可能少的内存存储状态表,这使得LCS算法在当前的应用中日益受到重视。

最长公共子序列

最长公共子序列

穷举法:
若要求两个序列X,Y的最长公共子序列, 先取得X,Y的所有子序列,并进行一一 比较,共有如下不同的组合:
Cm1 Cm2 ... Cmm 2m Cn1 Cn2 ... Cnn 2n
共要进行不同的比较:2 m+n
最长公共子序列的结构
设序列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的最长公共子序列。
最长公共子序列的定义:
•若给定序列X={x1,x2,…,xm},则另一序列 Z={z1,z2,…,zk},是X的子序列是指存在一个严格递增 下例标如序,列序列{i1,Zi2=,…{B,,ik}C使,得D对,于B所}是有序j=列1,X2=,…{A,,k有B:,zCj=,xiBj。, D,A,B}的子序列,相应的递增下标序列为{2,3,5, 7}。而子串则要求左右两元素在母串中为相邻。 •给定2个序列X和Y,当另一序列Z既是X的子序列又是 Y的子序列时,称Z是序列X和Y的公共子序列。 •给定2个序列X={x1,x2,…,xm}和Y={y1,y2,…,yn},找 出X和Y的最长公共子序列。
算法的改进
•如果只需要计算最长公共子序列的长度,则 算法的空间需求可大大减少。事实上,在计 算c[i][j]时,只用到数组c的第i行和第i-1行。 因此,用2行的数组空间就可以计算出最长公 共子序列的长度。进一步的分析还可将空间 需求减至O(min(m,n))。 •思考题:如何对程序进行改正,作为思考题。

最长公共子序列

最长公共子序列

最长公共子序列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)的长度}。

1143.最长公共子序列

1143.最长公共子序列

1143.最长公共⼦序列题⽬描述给定两个字符串 text1 和 text2,返回这两个字符串的最长公共⼦序列的长度。

如果不存在公共⼦序列,返回 0 。

⼀个字符串的⼦序列是指这样⼀个新的字符串:它是由原字符串在不改变字符的相对顺序的情况下删除某些字符(也可以不删除任何字符)后组成的新字符串。

例如,"ace" 是 "abcde" 的⼦序列,但 "aec" 不是 "abcde" 的⼦序列。

两个字符串的公共⼦序列是这两个字符串所共同拥有的⼦序列。

思路分析动态规划的最长公共⼦序列模板题⽬。

设定dp[i] [j]表⽰两个字符串前i个字符和前j个字符的最长公共⼦序列,那么当text1[i]==text2[j]的时候,就等于dp[i] [j]=dp[i-1] [j-1]+1,当不相等的时候,那么dp[i] [j]=max(dp[i-1] [j],dp[i] [j-1]);本题中为了⽅便讨论边界,计算dp[i] [j]的时候⽐较的是第i-1个字符和第j-1个字符,否则在计算dp[0] [0] 和dp[0] [1] 和dp[1] [0]会越界。

代码实现class Solution {public:int longestCommonSubsequence(string text1, string text2) {int len1=text1.size();int len2=text2.size();vector<vector<int>>dp(len1+1,vector<int>(len2+1,0));for(int i=1;i<=len1;i++){for(int j=1;j<=len2;j++){if(text1[i-1]==text2[j-1])dp[i][j]=dp[i-1][j-1]+1;elsedp[i][j]=max(dp[i-1][j],dp[i][j-1]);}}return dp[len1][len2];}};。

2 最长公共子序列

2 最长公共子序列

不用递归的情况下计算lcs(i, j). 不用递归的情况下计算 . 算法Lcs的时间复杂性显然是 的时间复杂性显然是O(nm) 算法 的时间复杂性显然是
int String::Lcs ( String y ) { int n = Length( ), m = y.Length( ); int lcs[MaxN][MaxM]; // MaxN和MaxM 是已定义的常数 int i, j; for ( i = 0; i <= n; i++) lcs[i][0] = 0; // 初始值 for ( j = 0; j <= m; j++) lcs[0][j] = 0; // 初始值 for ( i = 1; i <= n; i++) for ( j = 1; j <= m; j++) if ( str[i] ==y.str[j] ) lcs[i][j] = lcs[i-1][j-1] + 1; else lcs[i][j] = max(lcs[i-1][j], lcs[i][j-1]); return lcs[n][m]; }
穷举法
对于每一个X 的子序列,验证它是否是 验证它是否是Y 对于每一个 m的子序列 验证它是否是 n的子序 列. Xm有2m个子序列 每个子序列需要o(n)的时间来验证它是否是 n的 的时间来验证它是否是Y 每个子序列需要 的时间来验证它是否是 子序列. 子序列 的第一个字母开始扫描下去,如果不是则从 从Yn的第一个字母开始扫描下去 如果不是则从 第二个开始 运行时间: 运行时间 o(n2m)
作业
String String::Lcs ( String x, String y );

什么是最长公共子序列?

什么是最长公共子序列?

什么是最长公共子序列?
什么是最长公共子序列(LCS)?
最长公共子序列是指在两个序列中找到的最长的公共子序列,该子序列不需要在原序列中是连续的,但在两个序列中的顺序保持一致。

为了更好地理解最长公共子序列,我们可以通过一个具体的例子来说明。

假设我们有两个序列:ABCBDAB 和 BDCABA。

我们的目标是找到这两个序列的最长公共子序列。

首先,我们可以使用动态规划的方法来解决这个问题。

我们可以创建一个二维数组来存储两个序列之间的最长公共子序列的长度。

数组的行和列分别表示两个序列,数组中的每个元素表示对应位置的最长公共子序列的长度。

接下来,我们可以使用以下递推公式来填充数组:
如果两个序列的当前元素相等,则最长公共子序列的长度为前一个元素的最长公共子序列长度加1。

如果两个序列的当前元素不相等,则最长公共子序列的长度为前一个元素的最长公共子序列长度的最大值。

通过填充数组,我们可以得到最长公共子序列的长度。

然后,我们可以根据填充数组的过程来找到最长公共子序列。

最后,我们可以得到最长公共子序列为BCAB,长度为4。

总结起来,最长公共子序列是指在两个序列中找到的最长的公共子序列,不需要在原序列中是连续的,但在两个序列中的顺序保持一致。

我们可以使用动态规划的方法来解决这个问题,通过填充数组来得到最长公共子序列的长度,并根据填充数组的过程来找到最长公共子序列。

最长公共子序列

最长公共子序列

问题解决方案

由于应用了滚动数组,那么空间开销就 能够从5001*5001压缩到 2*5001 !!!
POJ 1159
#include<iostream> using namespace std; int max(int a,int b){ return a>b?a:b; } int main(int i,int j){ int n; while(cin>>n) { char* s1=new char[n+1]; char* s2=new char[n+1]; //s1的逆序列 int **dp=new int*[n+1]; //定义二维动态滚动数组 dp[0]=new int[n+1]; dp[1]=new int[n+1]; dp[0][0]=dp[1][0]=0;
分析
怎样求最少字符数? 先求原序列S的逆序列为S' 则最少需要补充的字符数 = 原序列S的长 度 — S和S'的最长公共子串长度

问题解决方案
几种不同的申请空间方法的区别: 1. 静态数组 开销大小为5001*5001的int是铁定超的. 2. 动态数组 单纯的申请动态数组是不能解决这个问题 的,动态数组只能增加空间利用率,但是本题最恶劣 的数组大小还是5001*5001,动态数组是不能改变这个 事实的 3. 滚动数组 这里重点讲一下滚动数组在这个题目中的 应用.滚动数组的目的就是减少空间开销.首先可以在纸 上简单模拟一下DP的转移过程.确定好最少行数或者列 数之后,重点就是在如何进行"滚动"以及如何用表达式 控制这个滚动.对于本题,可以用行数以0--1--0--1的滚动 方式,滚动表达式为i%2和(i-1)%2 ,没错,就是强大 的求余滚动

最长公共子序列

最长公共子序列

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最长公共子序列

1最长公共子序列

最长公共子序列日积月累算法与阅读评论字号:大中小订阅一个给定序列地子序列是在该序列中删去若干元素后得到地序列.最长公共子序列问题是给定两个序列{}和{},找出和地最长公共子序列,用动态规划算法可有效地解些问题.b5E2R。

最长公共子序列地结构:设{ , ... , } { , ... , }及它们地最长子序列{ , ... , }p1Ean。

则、若,则,且[] 是[] 和[] 地最长公共子序列、若,且, 则是[] 和地最长公共子序列、若, 且, 则是[] 和地最长公共子序列子问题地递归结构:DXDiT。

当, 时, [][] 当, > ; 时, [][] [][] 当, > ; 时, [][] { [][] , [][] }RTCrp。

由以上分析,先计算最优值,再构造最长公共子序列,源程序如下:<><>"";; 记录最长公共序列长度计算最优值( **){;获取字符串地长度() ();创建动太二维数组**;*[];( < )[] [];初始化数组(<) [][] ;(<) [][] ;[][] ;遍历记录最优值,并将标识存在数组中(<) (<){([] []){ ,则,且[] 是[] 和[] 地最长公共子序列[][] [][] ;[][] ;}([][] > [][]){ ,且, 则是[] 和地最长公共子序列[][] [][];[][] ;}{ , 且, 则是[] 和地最长公共子序列[][] [][];[][] ;}}释放空间( < )[];;}5PCzV。

构造最长公共子序列( **){递归中止条件();从[][]开始,用递归依其值在数组中搜索([][]){ 和地最长公共子序列是由()和()地最长公共子序列在尾部加上所得到地子序列();<< [];}([][]){ 和地最长公共子序列与()和地最长公共子序列相同();}{ 和地最长公共子序列与和()地最长公共子序列相同(); }} jLBHr。

最长公共子序列求解过程

最长公共子序列求解过程

最长公共子序列求解过程1. 什么是最长公共子序列在计算机科学中,最长公共子序列(Longest Common Subsequence,简称LCS)是指在多个序列中找到最长的子序列,使得这些子序列在所有序列中都按照原有的顺序出现,但是可以在某些序列中间有间隔。

2. 最长公共子序列的应用最长公共子序列问题在字符串处理、基因序列分析、文字相似度比较等领域有着广泛的应用。

例如,在文字相似度比较中,可以利用最长公共子序列算法来计算两段文字的相似程度。

3. 最长公共子序列求解过程最长公共子序列问题可以通过动态规划的方法来求解。

下面是最长公共子序列求解过程的详细步骤:步骤1:定义状态定义一个二维数组dp,其中dp[i][j]表示序列X的前i个字符和序列Y的前j个字符的最长公共子序列的长度。

步骤2:初始化边界条件将dp数组的第一行和第一列初始化为0,即dp[i][0] = 0和dp[0][j] = 0,表示空序列与任意序列的最长公共子序列长度为0。

步骤3:递推计算dp数组的值从dp[1][1]开始,依次计算dp[i][j]的值,具体计算方式如下:•如果X[i]等于Y[j],则dp[i][j] = dp[i-1][j-1] + 1;•如果X[i]不等于Y[j],则dp[i][j] = max(dp[i-1][j], dp[i][j-1]);通过上述递推公式,可以计算出dp数组中所有位置的值。

步骤4:回溯求解最长公共子序列从dp数组的右下角开始,根据dp数组的值回溯求解最长公共子序列。

具体步骤如下:•如果X[i]等于Y[j],则将X[i]添加到最长公共子序列中,同时i和j分别减1;•如果X[i]不等于Y[j],则根据dp[i][j-1]和dp[i-1][j]的值,选择dp[i][j]较大的方向移动一步。

重复上述步骤,直到i或j为0,则最长公共子序列求解完成。

4. 最长公共子序列的时间复杂度和空间复杂度最长公共子序列算法的时间复杂度为O(m n),其中m和n分别为序列X和序列Y的长度。

最长公共子序列

最长公共子序列

最长公共⼦序列给定两个长度分别为 NN 和 MM 的字符串 AA 和 BB,求既是 AA 的⼦序列⼜是 BB 的⼦序列的字符串长度最长是多少。

输⼊格式第⼀⾏包含两个整数 NN 和 MM。

第⼆⾏包含⼀个长度为 NN 的字符串,表⽰字符串 AA。

第三⾏包含⼀个长度为 MM 的字符串,表⽰字符串 BB。

字符串均由⼩写字母构成。

输出格式输出⼀个整数,表⽰最⼤长度。

数据范围1≤N,M≤10001≤N,M≤1000输⼊样例:4 5acbdabedc输出样例:3先来判断⼀下极端情况⼤概的估算⼀下时间复杂度再选择算法假如有a,b两串,a中的元素是n,n,n,n,n...b中的元素是n,n,n,n,n....(保证a<b)那a,b的最长公共⼦序列就是a的序列,然⽽a的序列中的⼦串每个元素都有选与不选两种⽅案,所以是2^n种指数型增长,⼀般数据范围⼤点的都不能枚举来做,必超时所以应该⽤dp来写令f[i][j]为集合A中1~i和B中1~j的公共⼦序列的最⼤值(根据a[i],b[j]是否相等再来分个类)然后划分a[i],b[j]包不包含在⼦序列⾥⾯,有四种状态,00,01,10,11第四类11;a[i],b[j]都选,然后a[i],b[j]是已经确定了的,是不变的,关键看前⾯不定的序列(前⾯的序列可以任意选,a[i],b[j]必选),f[i-1][j-1]+1就是这⼀类的最⼤值第⼀类00:这个就类似于背包问题,a[i],b[j]都不选,那f[i][j]此时的状态就是f[i-1][j-1]第⼆类01和第三类10⼀起说,这个y总讲的太⽜逼了,对的。

⾸先f[i-1][j]这个意思是不包含a[i],b[j]可以包含可以不包含,这个就是把01的状态全部覆盖了,虽然可能会有11的状态但没关系呀,没有总的界呀(01,11,10,00),同理可以⽤f[i-1][j]和f[i][j-1]这两种情况把10,01全部覆盖了,可能会涉及到⼀些11吧,但对结果没啥影响的这样说,第⼀类额00,f[i-1][j-1]就是不包含a[i]也不包含a[j]也是全部包含在a[i-1][j],a[i][j-1]的情况⾥⾯的,所以可以不⽤考虑的这个就是y总的主要思路#include<iostream>using namespace std;const int N=1010;char a[N],b[N];int n,m;int f[N][N];int main(){cin>>n>>m>>a+1>>b+1;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(a[i]==b[j])f[i][j]=max(f[i][j],f[i-1][j-1]+1);elsef[i][j]=max(f[i-1][j],f[i][j-1]); }}cout<<f[n][m]<<endl;return0;}结合思路,代码⼀看就懂。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#define MAXX 1000
using namespace std;
char* getstring(FILE * fp);
int lcsLength(char*x,char*y,int **b);
void lcs(int i,int j,char *x,int **b);
int main()
{
FILE *fp;
if((fp=fopen("附件 1.最长公共子序列输入数据.txt","r"))==NULL) {puts("FILE ERROR!");return 0;}
else
{
char* a=getstring(fp);
char* b=getstring(fp);
char* c=getstring(fp);
char* d=getstring(fp);
int **m = new int*[MAXX];
for(int i = 0;i<MAXX; i++)
m[i] = new int[MAXX];
lcsLength(a,b,m);
puts("AB最长公共子序列");
lcs(strlen(a),strlen(b),a,m);
puts("");
for(int i = 0;i<MAXX; i++)
m[i] = new int[MAXX];
lcsLength(c,d,m);
puts("CD最长公共子序列");
lcs(strlen(c),strlen(d),c,m);
puts("");
for(int i = 0;i<MAXX; i++)
m[i] = new int[MAXX];
lcsLength(a,d,m);
puts("AD最长公共子序列");
lcs(strlen(a),strlen(d),a,m);
}
}
char * getstring(FILE * fp)
{
char *s=(char *)malloc(1000*sizeof(char));
if(s==NULL) {puts("memory分配错误");}
while(fgetc(fp)!=10&&!feof(fp)) ;
int i;
int j=0;
for(i=0;i<8;i++)
{
char c;
int flag=0;
while((c=fgetc(fp))!=10&&!feof(fp))
{
if(c==':'||c==':') {j=j-1;flag=1;}
else s[j++]=c;
}
s[j]='\0';
if(flag==1) {fseek(fp,-3,1);while(fgetc(fp)!=10) fseek(fp,-2,1);break;} }
return s;
}
int lcsLength(char*x,char*y,int **b)
{
int m=strlen(x);
int n=strlen(y);
int **c = new int*[MAXX];
for(int i = 0;i<MAXX; i++)
c[i] = new int[MAXX];
for(int i=0;i<MAXX;i++)
for(int j=0;j<=MAXX;j++) c[i][j]=0;
int i,j;
for(i=1;i<m;i++) c[i][0]=0;
for(i=1;i<n;i++) c[0][i]=0;
for(i=1;i<=m;i++)
{
for(j=1;j<=n;j++)
{
if(x[i]==y[j])
{
c[i][j]=c[i-1][j-1]+1;
b[i][j]=1;
}
else if(c[i-1][j]>=c[i][j-1])
{
c[i][j]=c[i-1][j];
b[i][j]=2;
}
else
{
c[i][j]=c[i][j-1];
b[i][j]=3;
}
}
}
return c[m][n];
}
void lcs(int i,int j,char *x,int **b) {
if(i==0||j==0) return;
if(b[i][j]==1)
{
lcs(i-1,j-1,x,b);
cout<<x[i];
}
else if(b[i][j]==2) lcs(i-1,j,x,b);
else lcs(i,j-1,x,b);
}。

相关文档
最新文档