动态规划 A - 最大公共子序列 借鉴别人的

A - 最大公共子序列

 A subsequence of a given sequence is the givensequence with some elements (possible none) left out. Given a sequence X = <x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is asubsequence of X if there exists a strictly increasing sequence < i1, i2,..., ik > of indices of X such that for all j = 1,2,...,k, x ij =zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c,f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences Xand Y the problem is to find the length of the maximum-length commonsubsequence of X and Y.

Input

The programinput is from the std input. Each data set in the input contains two stringsrepresenting the given sequences. The sequences are separated by any number ofwhite spaces. The input data are correct.

Output

For eachset of data the program prints on the standard output the length of themaximum-length common subsequence from the beginning of a separate line.

Sample Input

abcfbc         abfcab
programming    contest 
abcd           mnp

Sample Output

4
2
0

菜鸟分析:

最长子串:连续 eg: abcdefgh  子串 abcde  fgh

最长子序列:可以不连续   eg: abcdefgh子序列 abcefh def

http://blog.csdn.net/hrn1216/article/details/51534607

(参考博客,他写的特别好,借鉴了一下)

(以下很多借鉴了别人的)

动态规划

       求解LCS问题,不能使用暴力搜索方法。一个长度为n的序列拥有 2的n次方个子序列,它的时间复杂度是指数阶,太恐怖了。解决LCS问题,需要借助动态规划的思想。

       动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。

        动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。

        与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。

        如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。


以我在第1小节举的例子(S1={1,3,4,5,6,7,7,8}和S2={3,5,7,4,8,6,7,8,2}),并结合上图来说:

       假如S1的最后一个元素 与 S2的最后一个元素相等,那么S1和S2的LCS就等于 {S1减去最后一个元素} 与 {S2减去最后一个元素} 的 LCS  再加上 S1和S2相等的最后一个元素。

       假如S1的最后一个元素 与 S2的最后一个元素不等(本例子就是属于这种情况),那么S1和S2的LCS就等于 : {S1减去最后一个元素} 与 S2 的LCS, {S2减去最后一个元素} 与 S1 的LCS 中的最大的那个序列。

递归公式

        第3节说了LCS的特征,我们可以发现,假设我需要求 a1 ... am 和 b1 .. b(n-1)的LCS 和 a1 ... a(m-1) 和 b1 .. bn的LCS,一定会递归地并且重复地把如a1... a(m-1) 与 b1 ... b(n-1) 的 LCS 计算几次。所以我们需要一个数据结构来记录中间结果,避免重复计算。

        假设我们用c[i,j]表示Xi 和 Yj 的LCS的长度(直接保存最长公共子序列的中间结果不现实,需要先借助LCS的长度)。其中X = {x1 ... xm},Y ={y1...yn},Xi = {x1 ... xi},Yj={y1... yj}。可得递归公式如下


//只需要得到最长子序列的长度,不需要输出

https://paste.ubuntu.com/p/cwFtfq42nB/

参考代码

import java.util.Scanner;

public class Main {

	static final int MAX = 500;
	public static void main(String[] args) {
		// TODO Auto-generated method stub

		Scanner cin = new Scanner(System.in);
		//多组输入
		while(cin.hasNext()){
			String s1=new String();
			String s2=new String();
			s1=cin.next();
			s2=cin.next();
			int [][]way=new int [MAX][MAX];
			for(int i=0;i<s1.length();i++){
				for(int j=0;j<s2.length();j++){
					if(s1.charAt(i)==s2.charAt(j)){
						way[i+1][j+1]=way[i][j]+1;
					}
					else {
						way[i+1][j+1]=Math.max(way[i][j+1], way[i+1][j]);
					}
				}	
			}	
			System.out.println(way[s1.length()][s2.length()]);	
		}
		
	}

}


猜你喜欢

转载自blog.csdn.net/dujuancao11/article/details/79545685