/**
* 动态规划之最长公共子序列问题:给定一个子序列 X = <x1,x2,...xm>,另一个子序列Z = <z1,z2,...zk>是X的子序列,如果存在X的一个严格递增下标序列
* <i1,i2,...ik>,使得对于所有j = 1,2,...k,有xij = zj。如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>子序列,对应下标i = <2,3,5,7>
* LCS问题:给定序列X=<x1,x2,...xn>和Y=<y1,y2...ym>,找出X和Y的最长公共子序列
* 设Z<z1,z2,...zk>是X和Y的任一个最长公共子序列,那么:
* 1) 若xn = ym,则zk = xn = ym 而且<z1,z2,...zk-1>是Xn-1和Ym-1的最长公共子序列
* 2) 若xn != ym 则zk!=xn 蕴含Z是Xn-1和Y的一个LCS
* 3) 若ym != xn 则zk!= ym蕴含Z是x和Ym-1的一个LCS
*
* 基于以上结论,可以得出一个递归解:
* 定义c[i][j]是序列Xi和Yj的LCS的长度则:
* --> 0 if i = 0 或者 j = 0
* c[i][j] = --> c[i-1][j-1] + 1 如果i>0,j>0,xi=yj
* --> max{c[i-1][j],c[i][j-1]} 如果i>0,j>0,xi != yj
* @author song
*
*/
/**
* 计算x和y的公共子序列长度表
* @param x
* @param y
* @return
*/
public static int[][] calculateCommonSubsequenceNum(char[] x, char[] y){
int n = x.length;
int m = y.length;
//记录各个LCS长度的二维表
int[][] c = new int[n+1][m+1];
//初始化:c[i][j] = 0 当i=0 or j=0
for(int i = 0; i <= m; ++i)
c[0][i] = 0;
for(int j = 0; j <= n; ++j)
c[j][0] = 0;
//注意c[1][1]记录的是 x[0]和y[0]的公共子序列长度,因为x和y的第一个元素不是x[1]和y[1],而是x[0]和y[0]
for( int i = 1; i <= n; ++i){
for(int j = 1; j <= m; ++j){
if( x[i-1] == y[j-1] )
c[i][j] = c[i-1][j-1] + 1;
else{
c[i][j] = Math.max(c[i-1][j], c[i][j-1]);
}
}
}
return c;
}
/**
* 找出一个最长公共子序列
* 找出LCS依赖于 {@link #calculateCommonSubsequenceNum(char[], char[])}的LCS长度序列表
* 根据最初分析的三个结论
* 1)若Z是X和Y的LCS,若xn=ym,则zk = xn = ym即X和Y的最后一个字符肯定出现在LCS中
* 2)若xn != ym,则Z肯定是 Xn-1和Ym的LCS 以及 Xn和Ym-1的LCS中更长得那一个序列,也就是说当xn!=ym时,可以转化为找 Xn-1和Ym的LCS/ Xn和Ym-1的LCS
* 更进一步,若c[n-1][m] > c[n][m-1],找Xn-1和Ym的LCS即可,因为他更长,反之找Xn和Ym-1的LCS
* 因此,从后向前扫描x和y序列,碰到相同则将该字符放入LCS,
* 若不相同,则比较c[n-1][m] > c[n][m-1],根据他们的值比较xn-1和ym 或者 xn和ym-1
*
* @param x
* @param y
* @return
*/
public static List<Character> findLongestLCS(char[] x,char[] y){
List<Character> result = new LinkedList<Character>();
int c[][] = calculateCommonSubsequenceNum(x, y);
int n = x.length - 1;
int m = y.length - 1;
while( n >= 0 && m >= 0){
if(x[n] == y[m]){
result.add(0, x[n]);
n--;m--;
}else{
if(c[n][m+1] > c[n+1][m])
n--;
else
m--;
}
}
return result;
}
测试代码:
public static void main(String[] args) {
char[] x = "10010101".toCharArray();
char[] y = "010110110".toCharArray();
List<Character> r = findLongestLCS(x, y);
System.out.println("The longest LCS:" + r.toString());
}
result:The longest LCS:[0, 1, 0, 1, 0, 1]
分享到:
相关推荐
在本例中,我们将聚焦于“最长公共子序列”(Longest Common Subsequence, LCS)问题,这是一种典型的动态规划应用。 最长公共子序列问题指的是给定两个序列X和Y,找到它们的最长子序列,这个子序列不必是连续的,...
动态规划是解决LCS问题的常用方法,它通过构建二维数组来存储子问题的解,从而避免了重复计算,提高了效率。 在动态规划解决LCS问题时,我们通常定义一个二维数组`dp`,其中`dp[i][j]`表示字符串S1的前i个字符与...
理解并掌握动态规划解决LCS问题的方法,对于提升算法能力和解决实际问题具有重要意义。在学习过程中,可以尝试对不同的输入数据进行测试,以加深对动态规划过程的理解,并优化算法性能,如使用空间优化减少存储需求...
标题"LCS.rar_LCS_Lcs.rar_公共子序列_动态规划"中,"LCS"代表最长公共子序列(Longest Common Subsequence),这是一个经典的计算机科学问题,特别是在算法和数据结构领域。它涉及到找到两个或更多序列中最长的子...
在IT领域,动态规划是一种强大的算法,用于解决各种复杂问题,包括寻找两个序列中的最长公共子序列(Longest Common Subsequence, LCS)。本压缩包"**LCS.rar_动态规划**"显然关注的是如何利用动态规划来处理这个...
### 动态规划:最长公共子串 LCS #### 长度与定义 **最长公共子串(Longest Common Substring, LCS)**是两个或多个字符串中的最长字符串,该字符串同时也是这些字符串的子串。这里需要注意区分子串与子序列的概念...
例如,“www.pudn.com.txt”可能是某个网站上关于LCS问题的讨论或者示例代码,而“动态规划lcs”可能是作者编写的一个动态规划求解LCS的程序。 通过阅读这些文件,你可以深入理解LCS问题的动态规划解决方案,包括...
最长公共子序列(lcs)使用动态规划解决采用c++编写
"动态规划 LCS&LIS 问题" 动态规划是计算机科学中的一种重要方法,用于解决复杂的问题。今天,我们将讨论动态规划在解决LCS(Longest Common Subsequence)和LIS(Longest Increasing Subsequence)问题中的应用。 ...
LCS 不仅在计算机科学中广泛应用,比如在比较文本、生物信息学等领域,而且是动态规划的经典问题之一。 ### 算法正确性的保证 1. **单调性**: - 在计算LCS的过程中,每次比较两个序列的一个字符后,至少有一个...
问题描述 东东有两个序列A和B。...这个题是基本的动态规划问题,LIS是最长上升子序列,LCS是最长公共子序列。 求解LIS就是设dp[i]为以当前元素结尾的最长上升序列,那么dp[i]=max(dp[j]∣j<i&&a
标题中的"LCS.rar_LCS_lcs dynamic"表明这是一个关于最长公共子序列(Longest Common Subsequence, LCS)问题的资源包,重点在于动态规划的实现。动态规划是一种解决复杂问题的有效算法,通常用于找到最优化的解决...
背包问题是动态规划的经典应用之一,涉及物品的选择和容量的限制,综合题可能包括0/1背包、完全背包等多种变体。 ### 14. 超级大背包 针对超大规模的背包问题,可能需要更高级的优化技巧和数据结构支持,如优先...
最长公共子序列(Longest Common Subsequence,简称LCS)是计算机科学中一种经典的问题,主要涉及到了动态规划这一算法设计思想。在这个问题中,给定两个字符串,目标是找到它们的最长子序列,这个子序列不必连续,...
【最长公共子序列(动态规划)】是一种经典的算法问题,主要应用于序列比对、文本处理等领域。本实验报告详尽地介绍了如何运用动态规划解决这一问题。 动态规划是一种解决复杂问题的有效方法,它通过将大问题分解为...
最长公共子序列(Longest Common Subsequence,简称LCS)是计算机科学中一个经典的问题,主要涉及字符串处理、算法设计和动态规划等领域。在给定的两个字符串中,LCS是指不改变顺序的情况下,这两个字符串共有的最长...
解决LCS问题的经典方法是采用动态规划,这种策略将问题分解为更小的子问题,然后通过构建一个二维数组来存储这些子问题的解。这个二维数组通常称为LCS表,它的大小为m+1(m为字符串A的长度)乘以n+1(n为字符串B的...
动态规划是一种强大的算法思想...动态规划的巧妙之处在于其能够将复杂问题分解为更小的子问题,通过存储子问题的解来避免重复计算,从而提高效率。学习并掌握这些经典应用,对于提升你在IT领域的专业技能具有重要意义。
本实验报告主要关注两个经典的动态规划应用:0-1 背包问题和最长公共子序列问题(LCS)。 1. 0-1 背包问题: 0-1 背包问题是组合优化问题的一个实例,它涉及到在给定的物品集合中选择一些物品放入容量有限的背包中...
LCS是计算机科学中一个经典的算法问题,主要涉及字符串处理、序列比较和动态规划等领域。在这个问题中,我们的目标是找到两个给定序列中最长的子序列,这个子序列不必连续,但要在两个原始序列中都存在。 描述中...