多个字符串的最长公共子序列

合集下载

详解Python最长公共子串和最长公共子序列的实现

详解Python最长公共子串和最长公共子序列的实现

详解Python最长公共⼦串和最长公共⼦序列的实现最长公共⼦串(The Longest Common Substring)LCS问题就是求两个字符串最长公共⼦串的问题。

解法就是⽤⼀个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。

然后求出对⾓线最长的1的序列,其对应的位置就是最长匹配⼦串的位置。

def find_lcsubstr(s1, s2):m=[[0 for i in range(len(s2)+1)] for j in range(len(s1)+1)] #⽣成0矩阵,为⽅便后续计算,⽐字符串长度多了⼀列mmax=0 #最长匹配的长度p=0 #最长匹配对应在s1中的最后⼀位for i in range(len(s1)):for j in range(len(s2)):if s1[i]==s2[j]:m[i+1][j+1]=m[i][j]+1if m[i+1][j+1]>mmax:mmax=m[i+1][j+1]p=i+1return s1[p-mmax:p],mmax #返回最长⼦串及其长度print find_lcsubstr('abcdfg','abdfg')运⾏得到输出:('dfg',3)最长公共⼦序列 (The Longest Common Subsequence)⼦串要求字符必须是连续的,但是⼦序列就不是这样。

最长公共⼦序列是⼀个⼗分实⽤的问题,它可以描述两段⽂字之间的“相似度”,即它们的雷同程度,从⽽能够⽤来辨别抄袭。

对⼀段⽂字进⾏修改之后,计算改动前后⽂字的最长公共⼦序列,将除此⼦序列外的部分提取出来,这种⽅法判断修改的部分,往往⼗分准确。

解法就是⽤动态回归的思想,⼀个矩阵记录两个字符串中匹配情况,若是匹配则为左上⽅的值加1,否则为左⽅和上⽅的最⼤值。

⼀个矩阵记录转移⽅向,然后根据转移⽅向,回溯找到最长⼦序列。

算法,最长公共子序列

算法,最长公共子序列

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

关于输出多个LCS(最长公共子序列)的简单技巧

关于输出多个LCS(最长公共子序列)的简单技巧

关于输出多个LCS(最长公共⼦序列)的简单技巧百度百科: ⼀个序列 S ,如果分别是两个或多个已知序列的⼦序列, 且是所有符合此条件序列中最长的,则 S 称为已知序列的最长公共⼦序列。

注意:S在已知序列中可以不连续;⽐如ABCBDAB和BDCABA的LCS为BCBA,BCBA不连续出现。

LCS通常利⽤动态规划算法求解,最简单的求解⽅式如《算法导论》所述: 1.设输⼊为X1X2…X m,Y1Y2…Y n,构造⼆维数组B、C; 其中B[i][j]存储C[i][j]的最优解指向,C[i][j]存储X[1…i]和Y[1…j]的LCS长度; 2.B、C数组同时更新: 2.1.令B[0][k]、C[0][k](k=0…n)和B[k][0]、C[k][0](k=0…m)为0; 2.2.按下标从⼩到⼤的顺序依次计算每⾏的B[i][j]和C[i][j],规则如下: ①.若X[i]=Y[j],则C[i][j]=C[i-1][j-1]+1,B[i][j]=0; ②.若X[i]!=Y[j],则C[i][j]=Max(C[i][j-1],C[i-1][j]),B[i][j]=1或2; 3.更新完B、C后,从C[m][n]开始递归输出,根据B[i][j]的指向打印LCS;相信⼤家都明⽩这个原理,简单的⽤⼀张图来说明⼀下: 1.箭头代表B[i][j]的值,其中⽤指向左上⽅的箭头代表0,←和↑代表1和2(或2和1); 2.箭头下⽅的数字为C[i][j]的值,即⼦问题X[1…i]和Y[1…j]的LCS长度;可是这样的构造只能输出⼀个LCS,但是我们发现BCBA、BCAB、BDAB都是该序列集的LCS。

为什么呢?因为该算法在C[i-1][j]=C[i][j-1]时,只记录了⼀种情况!即没有保存分⽀!如何简单的修改算法,以求得多个LCS呢?下⾯介绍⼀种改进的⽅法。

还是利⽤数组B、C,并且C的计算规则不变,下⾯修改B的计算规则: 1.若X[i]=Y[j],B[i][j]=0; 2.若X[i]!=Y[j],有以下判断: ①.若C[i-1][j]>C[i][j-1],则C[i][j]=C[i-1][j],B[i][j]=1; ②.若C[i-1][j]<C[i][j-1],则C[i][j]=C[i][j-1],B[i][j]=2; ③.若C[i-1][j]=C[i][j-1],则C[i][j]的长度任取,B[i][j]=3;此时⽤另⼀张图表⽰该算法: 1.⽤四种箭头表⽰B[i][j]的值,其中←和↑都存在时,表⽰C[i-1][j]=C[i][j-1]; 2.输出的时候采⽤正则表达式的思想:遇到B[i][j]=3时,同时对两种情况进⾏递归; 形式为“(←+↑)”,其中←和↑分别表⽰两个⼦问题的LCS;补充:(A+B),在正则表达式中意义为A或B,即“+”表⽰⼆选⼀的关系。

[DataStructure]LCSs——最长公共子序列和最长公共子串

[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中⼦序列,因此采⽤暴⼒算法的时间复杂度是指数级的,这显然不是⼀种好的解决⽅案。

下⾯我们看⼀下,如何使⽤动态规划的思想来解决最⼤公共⼦序列问题。

最长公共子序列代码

最长公共子序列代码

最长公共子序列代码最长公共子序列是指两个或多个字符串中,所有最长的公共子序列中,最长的一个。

求解最长公共子序列是经典的计算机科学问题,通常用于比较文件的差异,DNA序列的比较等领域。

以下是基于动态规划思想的最长公共子序列代码:```pythondef longest_common_subsequence(str1, str2):m = len(str1)n = len(str2)# 初始化二维数组dp = [[0] * (n + 1) for _ in range(m + 1)]for i in range(1, m + 1):for j in range(1, n + 1):if str1[i - 1] == str2[j - 1]:dp[i][j] = dp[i - 1][j - 1] + 1else:dp[i][j] = max(dp[i - 1][j], dp[i][j - 1])# 构造最长公共子序列lcs = ''i = mj = nwhile i > 0 and j > 0:if str1[i - 1] == str2[j - 1]:lcs = str1[i - 1] + lcsi -= 1j -= 1elif dp[i - 1][j] > dp[i][j - 1]:i -= 1else:j -= 1return lcs```以上代码以两个字符串str1和str2为输入,返回它们的最长公共子序列。

在代码中,首先定义了一个二维数组dp,其中dp[i][j]表示str1前i个字符和str2前j个字符的最长公共子序列的长度。

然后通过嵌套循环遍历两个字符串,更新dp数组。

如果str1第i个字符等于str2第j个字符,则dp[i][j]等于dp[i-1][j-1]+1,表示当前字符可以添加到最长公共子序列中;否则,dp[i][j]等于dp[i-1][j]和dp[i][j-1]的最大值,表示当前字符不能添加到最长公共子序列中,需要继续比较下一个字符。

[Python]最长公共子序列VS最长公共子串[动态规划]

[Python]最长公共子序列VS最长公共子串[动态规划]

[Python]最长公共⼦序列VS最长公共⼦串[动态规划]前⾔由于原微软开源的基于古⽼的perl语⾔的Rouge依赖环境实在难以搭建,遂跟着Rouge论⽂的描述⾃⾏实现。

Rouge存在N、L、S、W、SU等⼏⼤⼦评估指标。

在复现Rouge-L的函数时,便遇到了本博⽂的问题:求两串的最长公共⼦序列。

⼀参考⽂献全⽂参考均如下博⽂。

⼆最长公共⼦序列 & 最长公共⼦串的区别1、最长公共⼦序列(Longest Common Subsequence,LCS):在字符串A和字符串B中都出现的序列,且顺序与母串保持⼀致最长的那个序列。

2、最长公共⼦串(Longest Common Substring):相⽐LCS更加严格,序列必须连续出现,即公共的⼦字符串。

eg: csdnblog与belong,最长公共⼦序列为blog,最长公共⼦串为lo。

三程序设计与实现3.1 最长公共⼦序列def longestCommonSubsequence(seqA, seqB):"""最长公共⼦序列-----------[reference] 最长公共⼦序列与最长公共⼦串【动态规划】 https:///a515557595_xzb/article/details/88296989:param seqA::param seqB::return:"""m = len(seqA);n = len(seqB);init_unit={"len":0,"lcs":[]}dp = [[ init_unit ]*(n+1) for i in range(m+1)]; # m+1⾏, n+1列for i in range(0, m+1):for j in range(0, n+1):if i==0 or j==0:dp[i][j] = init_unit;elif seqA[i-1] == seqB[j-1]:tmp_str = copy.copy((dp[i-1][j-1])["lcs"]);tmp_str.append(seqA[i-1]);unit = {"len": (dp[i-1][j-1])["len"] + 1,"lcs": tmp_str}dp[i][j] = unit;elif seqA[i-1] != seqB[j-1]:if (dp[i-1][j])["len"] > (dp[i][j-1])["len"]: # 存储最长的信息dp[i][j] = dp[i-1][j];else:dp[i][j] = dp[i][j-1];else:pass;pass; # end inner for looppass; # end outer for loopreturn dp[m][n];print( longestCommonSubsequence("GM%$ABG", "gbndGFMABG") ) # {'len': 5, 'lcs': ['G', 'M', 'A', 'B', 'G']}print( longestCommonSubsequence(["G", "M", "%", "$", "A", "B", "G"], ["g","b", "n", "d", "G", "F", "M", "A", "B","G"] ) ); # {'len': 5, 'lcs': ['G', 'M', 'A', 'B', 'G']}3.2 最长公共⼦串def longestCommonSubstring(strA, strB):"""最长公共⼦串-----------[reference] 最长公共⼦序列与最长公共⼦串【动态规划】 https:///a515557595_xzb/article/details/88296989:param strA::param strB::return:"""m = len(strA);n = len(strB);init_unit={"len":0,"lcs":[]}dp = [[ init_unit ]*(n+1) for i in range(m+1)]; # m+1⾏, n+1列result ={"len":0, # 记录最长公共⼦串的长度"lcs": []};for i in range(0, m+1): # 考虑i为0或j为0的情况for j in range(0, n+1):if i==0 or j==0 or ( strA[i-1] != strB[j-1] ):dp[i][j] = init_unit;elif strA[i-1] == strB[j-1]:tmp_str = copy.copy((dp[i-1][j-1])["lcs"]);tmp_str.append(strA[i-1]);unit = {"len": (dp[i-1][j-1])["len"] + 1,"lcs": tmp_str}dp[i][j] = unit;if (dp[i][j])["len"] > result["len"]: # 存储最长的信息result = copy.copy( dp[i][j] );else:pass;pass; # end inner for looppass; # end outer for loopreturn result;print( longestCommonSubstring("GM%$ABG", "gbndGFMABG") ) # {'len': 3, 'lcs': ['A', 'B', 'G']}print( longestCommonSubstring(["G", "M", "%", "$", "A", "B", "G"], ["g","b", "n", "d", "G", "F", "M", "A", "B","G"] ) ); # {'len': 3, 'lcs': ['A', 'B', 'G']}四应⽤领域4.1 机器学习 > ⾃动⽂本摘要 / 机器翻译 / 机器阅读理解等任务中 > 评估指标 > Rouge-LRouge-L分类:句⼦级: 最长公共⼦序列⽂摘级: Union[多条句⼦] 最长公共⼦序列推荐博⽂:推荐论⽂: 《ROUGE: A Package for Automatic Evaluation of Summaries》。

用Python计算最长公共子序列和最长公共子串(转)

用Python计算最长公共子序列和最长公共子串(转)

⽤Python计算最长公共⼦序列和最长公共⼦串(转)1. 什么是最长公共⼦序列?什么是最长公共⼦串?1.1. 最长公共⼦序列(Longest-Common-Subsequences,LCS)最长公共⼦序列(Longest-Common-Subsequences,LCS)是⼀个在⼀个序列集合中(通常为两个序列)⽤来查找所有序列中最长⼦序列的问题。

这与查找最长公共⼦串的问题不同的地⽅是:⼦序列不需要在原序列中占⽤连续的位置。

最长公共⼦序列问题是⼀个经典的计算机科学问题,也是数据⽐较程序,⽐如Diff⼯具,和⽣物信息学应⽤的基础。

它也被⼴泛地应⽤在版本控制,⽐如Git⽤来调和⽂件之间的改变。

1.2 最长公共⼦串(Longest-Common-Substring,LCS)最长公共⼦串(Longest-Common-Substring,LCS)问题是寻找两个或多个已知字符串最长的⼦串。

此问题与最长公共⼦序列问题的区别在于⼦序列不必是连续的,⽽⼦串却必须是连续的。

2. 如何求解最长公共⼦序列?例如序列str_a=world,str_b=wordl。

序列wo是str_a和str_b的⼀个公共⼦序列,但是不是str_a和str_b的最长公共⼦序列,⼦序列word是str_a和str_b的⼀个LCS,序列worl也是。

暴⼒查找?寻找LCS的⼀种⽅法是枚举X所有的⼦序列,然后注意检查是否是Y的⼦序列,并随时记录发现的最长⼦序列。

假设X有m个元素,则X有2^m个⼦序列,指数级的时间,对长序列不实际。

分析问题,设str_a=<x1,x2,…,xm>和str_b=<y1,y2,…,yn>为两个序列,LCS(str_a,str_b)表⽰str_a和str_b的⼀个最长公共⼦序列,可以看出如果str_a[m] == str_b[n],则LCS (str_a, str_b) = str_a[m] + LCS(str_a[1:m-1],str_b[1:n-1])如果str_a[m] != str_b[n],则LCS(str_a,str_b)= max{LCS(str_a[1:m-1], str_b), LCS (str_a, str_b[n-1])}LCS问题也具有重叠⼦问题性质:为找出LCS(str_a,str_b),可能需要找LCS(str_a[1:m-1], str_b)以及LCS (str_a, str_b[n-1])。

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

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

多个字符串的最长公共子序列
最长公共子序列(LCS)是DP中的经典问题,是指多个字符串可具有的长度最大的公共的子序列。

一个字符串的子序列,是指从该字符串中去掉任意多个字符后剩下的字符在不改变顺序的情况下组成的新字符串。

LCS有多种求解方法,包括暴力求解、动态规划、记号法等。

其中,动态规划法是一种常见的方法,通过构建状态转移方程来求解。

LCS在字符串编辑距离、最长递增子序列等方面有应用。

例如,在字符串编辑距离中,LCS可以用于衡量两个字符串的相似度。

如果你想进一步了解LCS或其他相关算法,可以查阅相关资料或咨询专业人士。

相关文档
最新文档