- 浏览: 899391 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
LCS:又称 最长公共子序列。 其中子序列(subsequence)的概念不同于串的子串。它是一个不一定连续但按顺序取自字符串X中的字符序列。 例如:串"AAAG"就是串“CGATAATTGAGA”的一个子序列。
字符串的相似性问题可以通过求解两个串间的最长公共子序列(LCS)来得到。 当然如果使用穷举算法列出串的所有子序列,一共有2^n种,而每个子序列是否是另外一个串的子序列又需要O(m)的时间复杂度,因此这个穷举的方法时间复杂度是O(m*(2^n))指数级别,效率相当的可怕。我们采用动态规划算法来解决这个问题。
动态规划算法解决最长公共子序列
假如我们有两个字符串:X=[0,1,2....n] Y=[0,1,2...m]。我们定义L(i, j)为X[0...i]与Y[0...j]之间的最长公共子序列的长度。通过动态规划思想(复杂问题的最优解是子问题的最优解和子问题的重叠性质决定的)。我们考虑这样两种情况:
(1) 当X[i]=Y[j]时, L(i, j)=L(i-1, j-1)+1 。证明很简单。
(2) 当X[i]!=Y[j]时, 说明此事X[0...i]和Y[0...j]的最长公共子序列中绝对不可能同时含有X[i]和Y[j]。那么公共子序列可能以X[i]结尾,可能以Y[j]结尾,可以末尾都不含有X[i]或Y[j]。因此
L(i, j)= MAX{L(i-1 , j), L(i, j-1)}
LCS动态规划Java源代码
package net.hr.algorithm.string; /** * 最长公共子串LCS * @author heartraid */ public class LCS { /**字符串X的字符数组*/ private char[] charArrayX=null; /**字符串Y的字符数组*/ private char[] charArrayY=null; public LCS(String sa,String sb){ charArrayX=new char[sa.length()+1]; System.arraycopy(sa.toCharArray(),0,charArrayX,1,sa.length()); charArrayY=new char[sb.length()+1]; System.arraycopy(sb.toCharArray(),0,charArrayY,1,sb.length()); } /** * 得到最长公共子序列的长度 */ public void getLCS(){ int[][] length=new int[charArrayX.length+1][charArrayY.length+1]; for(int m=1;m<charArrayX.length;m++) for(int n=1;n<charArrayY.length;n++){ if(charArrayX[m]==charArrayY[n]){ length[m][n]=length[m-1][n-1]+1; } else length[m][n]=max(length[m-1][n],length[m][n-1]); } //打印最长公共子序列 String lcstr=""; int x=charArrayX.length-1; int y=charArrayY.length-1; while(x>=1&&y>=1){ if(charArrayX[x]==charArrayY[y]){ lcstr=charArrayX[x]+lcstr; x--; y--; }else{ if(length[x-1][y]<=length[x][y-1]) y--; else x--; } } System.out.println("最长公共子序列为:"+lcstr+" [length="+lcstr.length()+"]"); } /** * 取最大值 */ private int max(int m,int n){ return m>n?m:n; } /** * 测试 */ public static void main(String[] args) { LCS lcs=new LCS("GTTCCTAATA","CGATAATTGAGA"); lcs.getLCS(); } }
这里解释一下上面的代码,其中getLength()的作用是递归获取最长公共子串的长度,并得到递归过程中每个子串之间最长公共子串长度的状态表lcs[][],这张表运行的结果如下:
C G A T A A T T G A G A
0 0 0 0 0 0 0 0 0 0 0 0 0
G 0 0 1 1 1 1 1 1 1 1 1 1 1
T 0 0 1 1 2 2 2 2 2 2 2 2 2
T 0 0 1 1 2 2 2 3 3 3 3 3 3
C 0 1 1 1 2 2 2 3 3 3 3 3 3
C
0 1
1 1 2 2 2 3 3 3 3 3 3
T 0 1 1 1 2
2 2 3 4 4 4 4 4
A 0 1 1 2 2 3
3 3 4 4 5 5 5
A 0 1 1 2 2 3 4
4 4 4 5 5 6
T 0 1 1 2 3 3 4 5 5
5 5 5 6
A 0 1 1 2 3 4 4 5 5 5 6 6 6
红色数字的位置就揭示了最长公共子序列: CTATTA。也就是说分析这张表就可以得到最长公共子序列字符串。
为什么呢?因为通过表的回溯过程,从后向前重构了一个最长公共子序列。对于任何位置lcs[i][j],确定是否X[i]=Y[j]。如果是,那么X[i]必是最长公共子序列的一个字符。如果否,那么移动到lcs[i,j-1]和lcs[i-1, j]之间的较大者。
动态规划方法LCS效率:
动态规划方法构造最长公共子序列需要O(m*n)的代价,另外,如果想要得到最长公共子序列,又需要O(m+n)的时间来读取csl[][]数组。尽管如此,其时间复杂度仍然比蛮力穷举的指数级别要强的多。
问题拓展:设A,B,C是三个长为n的字符串,它们取自同一常数大小的字母表。设计一个找出三个串的最长公共子串的O(n^3)的时间算法。 (来自《Algorithm Design》(中文版:算法分析与设计) - Chapter9 - 文本处理 - 创新题C-9.18)
分析:可以通过《LCS 最长公共子序列 》的动态规划算法,设计Java源代码如下:
public class TriLCS{ char[] charA=null; char[] charB=null; char[] charC=null; public TriLCS(String sa,String sb,String sc){ charA=new char[sa.length()+1]; System.arraycopy(sa.toCharArray(),0,charA,1,sa.length()); charB=new char[sb.length()+1]; System.arraycopy(sb.toCharArray(),0,charB,1,sb.length()); charC=new char[sc.length()+1]; System.arraycopy(sc.toCharArray(),0,charC,1,sc.length()); } public void getTriLCS(){ int[][][] length=new int[charA.length][charB.length][charC.length]; for(int a=1;a<charA.length;a++) for(int b=1;b<charB.length;b++) for(int c=1;c<charC.length;c++){ if(charA[a]==charB[b]&&charA[a]==charC[c]){ length[a][b][c]=length[a-1][b-1][c-1]+1; } else if(charA[a]==charB[b]&&charA[a]!=charC[c]){ length[a][b][c]=max(length[a-1][b-1][c],length[a][b][c-1]); } else if(charA[a]==charC[c]&&charA[a]!=charB[b]){ length[a][b][c]=max(length[a-1][b][c-1],length[a][b-1][c]); } else if(charB[b]==charC[c]&&charA[a]!=charB[b]){ length[a][b][c]=max(length[a][b-1][c-1],length[a-1][b][c]); } else{ length[a][b][c]=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]); } } //打印最长公共子序列 String lcstr=""; int a=charA.length-1; int b=charB.length-1; int c=charC.length-1; while(a>=1&&b>=1&&c>=1){ if(charA[a]==charB[b]&&charA[a]==charC[c]){ lcstr=charA[a]+lcstr; a--; b--; c--; } else if(charA[a]==charB[b]&&charA[a]!=charC[c]){ if(length[a-1][b-1][c]<=length[a][b][c-1]) c--; else{ a--; b--; } } else if(charA[a]==charC[c]&&charA[a]!=charB[b]){ if(length[a-1][b][c-1]<=length[a][b-1][c]) b--; else{ a--; c--; } } else if(charB[b]==charC[c]&&charA[a]!=charB[b]){ if(length[a][b-1][c-1]<=length[a-1][b][c]) a--; else{ b--; c--; } } else{ int maxize=max(length[a-1][b][c],length[a][b-1][c],length[a][b][c-1],length[a-1][b-1][c],length[a-1][b][c-1],length[a][b-1][c-1]); if(maxize==length[a-1][b][c]) a--; if(maxize==length[a][b-1][c]) b--; if(maxize==length[a][b][c-1]) c--; if(maxize==length[a-1][b-1][c]){ a--; b--; } if(maxize==length[a-1][b][c-1]){ a--; c--; } if(maxize==length[a][b-1][c-1]){ b--; c--; } } } System.out.println("最长子串为:"+lcstr+"(length="+length[charA.length-1][charB.length-1][charC.length-1]+")"); } /** * 取最大值 */ private int max(int m,int n){ return m>n?m:n; } /** * 取最大值 */ private int max(int x,int y,int z,int k,int m,int n){ int maxizen=0; if(maxizen<x) maxizen=x; if(maxizen<y) maxizen=y; if(maxizen<z) maxizen=z; if(maxizen<k) maxizen=k; if(maxizen<m) maxizen=m; if(maxizen<n) maxizen=n; return maxizen; } public static void main(String[] args){ TriLCS tri=new TriLCS("aadsbbbcs","adsabcs","adbsbsdcs"); tri.getTriLCS(); } }
发表评论
-
★经典问题—链表中的环问题
2010-06-29 14:43 4462转载:http://www.cppblog.com ... -
★经典问题—元素选择问题
2010-05-24 10:53 3364元素选择问题 : 给定线性序集中n个元素和一个整数k( ... -
【串和序列处理 8】最长平台问题
2010-04-28 16:41 37351、经典最长平台算法 已知一个已经从小到大 ... -
【排序结构7】 基数排序
2010-04-20 16:17 4592《桶排序 》中我们能够看到,数据值的范围越大,可能需要桶的个 ... -
【排序结构6】 桶排序
2010-04-19 20:28 23103从《基于比较的排序结构总结 》中我们知道:全依赖“比较”操作的 ... -
【排序结构5】 基于比较的内部排序总结
2010-04-18 16:15 6772★ 基于“比较”操作的内部排序性能大PK ... -
【排序结构4】 归并排序
2010-04-17 16:29 3330归并排序 O(N*logN) 是另一种效率很高的排序方法。&q ... -
【排序结构3】 选择排序
2010-04-14 21:10 3693(1) 简单选择排序 O(N^2) 一趟简单选择排序 ... -
【排序结构2】交换排序
2010-04-14 11:04 26651、起泡排序 O(N^2) ... -
【排序结构1】插入排序
2010-04-13 17:11 30601、基本概念介绍 (1) 如果待排序列中有两个 ... -
【串和序列处理 7】LIS 最长递增子序列
2010-03-25 16:37 5850LIS: 给定一个字符串序列S={x0,x1,x2,.. ... -
【串和序列处理 5】KMP子串匹配算法
2010-03-22 19:59 9195模式匹配: 在字符串 ... -
★经典问题—欧几里得求最大公约数
2010-03-20 19:21 3401问题:快速求取正整数a,b的最大公约数? ... -
【串和序列处理 4】Suffix Trie 子串匹配结构
2010-03-20 15:15 9156Suffix Trie : 又称后 ... -
【串和序列处理 3】Trie Tree 串集合查找
2010-03-18 13:40 17750Trie 树, 又称字典树,单词查找树。它来源于retr ... -
【串和序列处理 2】字符串编辑距离算法
2010-03-15 08:45 11121我们来看一个实际应用。现代搜索技术的发展很多以提供优质、高效的 ... -
【串和序列处理 1】PAT Tree 子串匹配结构
2010-03-14 19:10 11331Patricia Tree 简称PAT tree ... -
【查找结构6】动态查找树比较
2010-03-12 13:32 11338我们这个专题介绍的动态查找树主要有: 二叉查找树(BST),平 ... -
【查找结构4】红黑树 [RBT]
2010-03-10 10:58 10638大部分转载:http://yanglongylj.blog.1 ... -
【查找结构5】多路查找树/B~树/B+树
2010-03-09 11:56 18242在前面专题中讲的BST、A ...
相关推荐
最长公共子序列(Longest Common Subsequence,简称LCS)是计算机科学中一个经典的问题,主要涉及算法和数据结构领域,特别是在字符串处理、生物信息学和比较编程中有着广泛的应用。LCS问题寻找的是两个序列中长度...
最长公共子序列问题(Longest Common Subsequence,LCS)是计算机科学中一个经典的问题,它是指给定两个序列X和Y,找出它们的最长公共子序列。该问题具有重要的理论和实际意义,在很多领域都有应用,如数据压缩、...
最长公共子序列(Longest Common Subsequence,简称LCS)是计算机科学中一种经典的问题,主要出现在序列比对、文本编辑距离等领域。在两个给定的字符串中,LCS是指不考虑字符顺序的最长子串,它同时存在于这两个字符...
**最长公共子序列(Longest Common Subsequence, LCS)算法详解** 在计算机科学中,LCS算法是一个经典的字符串处理问题,用于寻找两个序列的最长子序列,这个子序列不必是连续的,但必须保持原序列的相对顺序。该...
实现了求最长公共子序列的算法,内容简单易懂,代码也很短
最长公共子序列(Longest Common Subsequence,LCS)是一个经典的计算机科学问题,涉及序列比较和算法设计。在本实验报告中,我们将深入探讨如何利用动态规划方法解决这一问题。 首先,LCS问题旨在找到两个给定序列...
最长公共子序列(Longest Common Subsequence,LCS)是一个经典的计算机科学问题,它涉及到序列比对和字符串处理。在两个或多个序列中,LCS是指没有改变原有顺序的情况下,存在于所有序列中的最长子序列。这个问题在...
在深入解析给定代码之前,我们先来了解一下“最长公共子序列”(Longest Common Subsequence,简称LCS)的基本概念及其在计算机科学中的应用。LCS问题是一种典型的动态规划问题,广泛应用于生物信息学、文本编辑和...
最长公共子序列(Longest Common Subsequence,LCS)是计算机科学中一种经典的字符串问题,主要应用于比较两个序列的相似性。在这个C++算法实验中,我们关注的是如何找到两个字符串之间的最长公共子序列,而不仅仅是...
最长公共子序列(Longest Common Subsequence,LCS)是计算机科学中一种经典的字符串问题,主要涉及算法设计和分析。它的目标是找到两个给定序列(通常为字符串)的最长子序列,该子序列在原序列中不需连续,但必须...
在讨论最长公共子序列(Longest Common Subsequence,简称LCS)问题时,通常会提及两种主要的算法实现方式:一种时间复杂度为O(n^2),另一种则通过优化达到O(nlogn)的时间复杂度。下面我们将详细介绍这两种算法。 *...
求A、B所有公共子序列中最长的序列的长度。 输入: 输入共两行,每行一个由字母和数字组成的字符串,代表序列A、B。A、B的长度不超过200个字符。 输出: 一个整数,表示最长各个子序列的长度。 格式:printf...
数学上,如果给定两个序列 `X = {x1, x2, ..., xm}` 和 `Y = {y1, y2, ..., yn}`,那么寻找它们的最长公共子序列(LCS)的目标就是找到一个最长的序列 `Z`,使得 `Z` 同时是 `X` 和 `Y` 的子序列。 #### 三、动态...
最长公共子序列(Longest Common Subsequence,LCS)算法是一种经典的计算机科学问题,主要应用于比较和分析两个或多个序列的相似性。在文本编辑、生物信息学、数据挖掘等领域有着广泛的应用。LCS的基本思想是寻找两...
最长公共子序列问题是字符串处理中的经典问题之一,其应用广泛,不仅限于文本编辑和生物信息学,在数据挖掘、机器学习等领域也有其独特的价值。掌握LCS算法的原理与实现,对于提升编程能力和理解数据结构有重要意义...
算法系列之六:最长公共子序列(LCS)问题(连续子序列)的三种解法 本文档总结了解决最长公共子序列(LCS)问题的三种解法,针对连续子序列的情况。LCS 问题有两种定义子序列的方式:一是子序列不要求连续,二是子...
【最长公共子序列(动态规划)】是一种经典的算法问题,主要应用于序列比对、文本处理等领域。本实验报告详尽地介绍了如何运用动态规划解决这一问题。 动态规划是一种解决复杂问题的有效方法,它通过将大问题分解为...