LCS求最长公共子序列(DP)

动态规划并不是一种算法,而是一种解决问题的思路。典型的动态规划问题,如最长公共子序列(LCS),最长单调子序列(LIS)等。

动态规划分为四个步骤:

1.判断问题是否具有最优子结构

这里以LCS为例,X={x1,x2,...,xi};Y={y1,y2,...,yj}。最长公共子序列Z={z1,z2,...,zk};

①如果xi=yj,那么zk=xi=yj,且Zk-1是序列Xi-1和Yj-1的LCS;

②如果xi≠yj,那么zk≠xi;且Zk是序列Xi-1和Yj的LCS;

③如果xi≠yj,那么zk≠yj;且Zk是序列Xi和Yj-1的LCS;

可以用反证法证明上述子结构的成立。

2.一个递归解

设c[i,j]是Xi和Yj的LCS的长度,i=0或j=0时,c[i,j]=0;

c[i,j]=0   (i=0或j=0)

c[i,j]=c[i-1,j-1]   (i,j>0;xi=yj)

c[i,j]=max{c[i-1,j],c[i,j-1]}   (i,j>0;xi≠yj)

3.计算LCS的长度

c[i,j]为递归解,那么有多少个不同的递归解呢?O(m*n)。即要有重叠子问题,而不是每次都要解决新的问题。至于重叠子问题,需从底向上求。每次只需索引之前较小规模的子问题即可。

从底向上,求解c[i,j]。还需维护b[i][j]以简化最优解的结构。

例如,设所给的两个序列为X=<A,B,C,B,D,A,B>和Y=<B,D,C,A,B,A>。由算法LCS_LENGTH和LCS计算出的结果如图2所示。



package hello;

/*
* 本代码通过动态规划法获取2个序列之间的最长公共子序列,并输出序列的长度。
* 通过动态规划法解决的问题往往都具有最优子结构性质和重叠子问题性质。
* 本题的最优子结构性质证明如下:
* 对于2个序列的最长公共子序列。如果x[m]=y[n],则最长公共子序列就是x[m-1]和y[n-1]的最长公共子序列+1。
* 如果x[m]和y[n]不相等,那么最长公共子序列就是x[m]和y[n-1]或x[m-1]和y[n]之间最长公共子序列的最大值。
* 如果子序列的公共子序列不能达到最大,则该公共子序列一定不是最大的,与假设矛盾。
*
* 递归方程为:c[i][j]=0 当 i=0,或j=0
* c[i][j]=c[i-1][j-1]+1 当i,j>0;x[i]=y[j];
* max{c[i][j-1],c[i-1][j]} i,j>0;x[i]不等于y[j]
*
*
* */
public class getLongestString {
public static void getLongest(char[] x,char[] y,int[][] longest,int[][] ch){
//将最长序列的边界值进行初始化
for(int i=0;i<x.length;i++) longest[i][0] = 0;
for(int i=0;i<y.length;i++) longest[0][i] = 0;
//由底向上根据刚刚的递推公式一层一层求解longest[i][j],通过ch[i][j]来记录字母
for(int i=1;i<x.length;i++)
for(int j=1;j<y.length;j++){
if(x[i] == y[j]) {longest[i][j] = longest[i-1][j-1]+1;ch[i][j]=1;}
else if(longest[i-1][j]>longest[i][j-1]){
longest[i][j] = longest[i-1][j];
ch[i][j]=2;
}
else {
longest[i][j] = longest[i][j-1];
ch[i][j] = 3;
}
}
System.out.println("最长公共子序列长度为:"+longest[x.length-1][y.length-1]);
System.out.print("该序列是:");
getString(x.length-1,y.length-1,x,y,ch);
}
//获取最长的公共子序列,当出现第一种情况时,就可以提取出一个字母
public static void getString(int i,int j,char[] x,char[] y,int[][] ch){
if(i==0 || j==0) return;
else if(ch[i][j]==1) {
getString(i-1,j-1,x,y,ch);
System.out.print(x[i]);
}
else if(ch[i][j]==2)
getString(i-1,j,x,y,ch);
else
getString(i,j-1,x,y,ch);
}
public static void main(String[] args){
String str1 = " skowcgk";
String str2 = " dsofdwvk";
char[] ch1 = str1.toCharArray();
char[] ch2 = str2.toCharArray();
int[][] longest = new int[ch1.length][ch2.length];
int[][] ch = new int[ch1.length][ch2.length];
getLongest(ch1,ch2,longest,ch);
}
}
时间: 2024-10-27 13:51:13

LCS求最长公共子序列(DP)的相关文章

LCS 求最长公共子序列

最长公共子序列不需要字符连续出现和字串不同 //LCS 求最长公共子串模板题  Common Subsequence 描述 A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm> another sequence Z = <z1, z2, ..., zk> is

求最长公共子序列-DP问题

Longest common subsequence problem The longest common subsequence (LCS) problem is the problem of finding the longest subsequence common to all sequences in a set of sequences (often just two sequences). It differs from the longest common substring p

(hdu step 3.2.2)Common Subsequence(简单dp:求最长公共子序列的长度)

在写题解之前给自己打一下广告哈~..抱歉了,希望大家多多支持我在CSDN的视频课程,地址如下: http://edu.csdn.net/course/detail/209 题目: Common Subsequence Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 976 Accepted Submission(s): 538   Probl

[algorithm]求最长公共子序列问题

最直白方法:时间复杂度是O(n3), 空间复杂度是常数 reference:http://blog.csdn.net/monkeyandy/article/details/7957263 /** ** [email protected] ** http://blog.csdn.net/MonkeyAndy **/ 首先介绍动态规划方法的相关知识 动态规划方法的基本思想: 分成若干个子问题,先求解子问题,然后根据子问题的解求得原问题的解.经分解得到的子问题往往不是互相独立的.可重复利用! 其核心思

HDU 1243 反恐训练营 (动态规划求最长公共子序列)

反恐训练营 Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) Total Submission(s): 3040    Accepted Submission(s): 693 Problem Description 当今国际反恐形势很严峻,特别是美国"9.11事件"以后,国际恐怖势力更是有恃无恐,制造了多起骇人听闻的恐怖事件.基于此,各国都十分担心恐怖势力会对本国社会造

lcs(最长公共子序列),dp

lcs(最长公共子序列) 求两个序列的lcs的长度,子序列可不连续 dp[i][j]=dp[i-1][j-1]+1(a[i]==b[i]) dp[i][j]=max(dp[i-1][j],dp[i][j-1])(a[i]!=b[i]) memset(dp,0,sizeof(dp)); for(int i=1;i<=n1;i++){ for(int j=1;j<=n2;j++){ if(a[i]==b[j]) dp[i][j]=dp[i-1][j-1]+1; else dp[i][j]=max(

POJ 1458 Common Subsequence (DP+LCS,最长公共子序列)

题意:给定两个字符串,让你找出它们之间最长公共子序列(LCS)的长度. 析:很明显是个DP,就是LCS,一点都没变.设两个序列分别为,A1,A2,...和B1,B2..,d(i, j)表示两个字符串LCS长度. 当A[i] = B[j] 时,这个最长度就是上一个长度加1,即:d(i, j) = d(i-1, j-1) + 1; 当A[i] != B[j] 时,那就是前面的最长长度(因为即使后面的不成立,也不会影响前面的),即:d(i, j) = max{d(i-1, j), d(i, j-1)}

【算法】 求最长公共子序列

最长公共子序列 算法这玩意儿我完全是外行,因为从头开始就不是这个专业的再加上从小就对逻辑性强的东西苦手..所以一直没什么机会也没什么兴趣学.去年刚开始学习了python的那段时间曾经碰到过几个算法比较高级的问题,当时觉得果然这不是我的能力能驾驭的了的..总之是先记录了下来,但是对于算法这块将来的拓展和进一步学习,其实我挺没信心的 = = 问题:最长公共子序列问题(Longest Common Sequence) 子序列是指一个字符串抽掉0到若干个字符后剩下的字符串,抽取的字符不一定相邻也不一定有

hdu 1159 common sequence (最长公共子序列 dp)

http://acm.hdu.edu.cn/showproblem.php?pid=1159 题意 : 给出两个字符串 求出最长公共子序列 思路: if(str1[i]==str2[j]) { dp[i][j]=max(dp[i-1][j-1]+1,max(dp[i-1][j],dp[i][j-1])); } else dp[i][j]=max(dp[i-1][j],dp[i][j-1]); #include<cstdio> #include<cstring> #include&l