最长公共子序列--求最长公共子串长度

最长公共子序列算法应用非常广泛:比如染色体中DNA片段的的研究,基于最长公共子序列的微博谣言溯源研究等等。所以掌握与应用该基础算法是十分必要的。下面就简要阐述我对它的见解。
最长公共子序列的定义:
给定两个字符串:如
1.A B D C A C B
2.B A D B C
找到字符串1和字符串2的最长公共子序列
必要条件(1):子序列必须是有序的;
(2) : 子序列的长度最大;
注意 : 最长公共子序列不唯一
字符串1和字符串2的最长公共子序列: (1)B A C ,(2) A D B (3)…等等
应用穷举法可以得到我们想要的答案。但是时间复杂度为O(2^m*n)。是指数级别的复杂度,对于长序列是不适用的。因此我们使用动态规划法来求解。
刻画最长公共子序列问题的最优子结构
设X=x1x2…xm和Y=y1y2…yn是两个序列,Z=z1z2…zk是这两个序列的一个最长公共子序列。
1. 如果xm=yn,那么zk=xm=yn,且Zk-1是Xm-1,Yn-1的一个最长公共子序列;
2. 如果xm≠yn,那么zk≠xm,意味着Z是Xm-1,Y的一个最长公共子序列;
3. 如果xm≠yn,那么zk≠yn,意味着Z是X,Yn-1的一个最长公共子序列。

递归定义最优解
最长公共子序列--求最长公共子串长度_第1张图片
package 动态规划;

public class 自底向上求最长公共子串长度 {

public static int lcs(char[] x,char[] y,int i,int j,int[][] bak)
{
	for(int m = 0; m <= i; m++)
	{
		for(int n = 0 ; n <= j; n++)
		{
			if(m == 0 || n ==0) bak[m][n] = 0;
			else if(x[m] == y[n]) bak[m][n] = bak[m-1][n-1]+1;
			else bak[m][n] = max (bak[m-1][n],bak[m][n-1]);
		}
	}
	return bak[i][j];
}

private static int max(int a, int b) {
	if(a > b) return a;
	return b;
}

public static void main(String[] args) {

	String s1 = "ABCBDAB";
	char[] c1 = new char[s1.length() + 1];//带0号字符的字符数组
	char[] t1 = s1.toCharArray();	//toCharArray() 方法将字符串转换为字符数组
	c1[0] = (char)0;
	for(int i = 1; i < t1.length;  i++)
	{
		c1[i + 1] = t1[i];
	}
	String s2 = "BDCABA";
	char[] c2 = new char[s2.length() + 1];//带0号字符的字符数组
	char[] t2 = s2.toCharArray();
	c2[0] = (char)0;
	for(int i = 1; i < t2.length;  i++)
	{
		c2[i + 1] = t2[i];
	}
	
	int[][] bak = new int[c1.length][c2.length];
	
	System.out.println(lcs(c1,c2,c1.length-1  ,c2.length-1 ,bak));
}

}

/***********************************************/
package 动态规划;

public class 备忘录法求最长公共子串长度 {
//缺点是复杂度与自底向上的算法一样,但实际上更占资源,时间上慢
public static int lcs(char[] x,char[] y,int i,int j,int[][] bak)
{
if(bak[i][j] != -1) return bak[i][j];
if(i == 0 || j == 0) return bak[i][j] = 0;
else if(x[i] == y[j]) return bak[i][j] = lcs(x,y,i-1,j-1,bak)+1;
else bak[i][j] = max(lcs(x,y,i-1,j,bak),lcs(x,y,i,j-1,bak));
return bak[i][j];
}

private static int max(int a, int b) {
	if(a > b) return a;
	return b;
}

public static void main(String[] args) {

	String s1 = "ABCBDAB";
	char[] c1 = new char[s1.length() + 1];//带0号字符的字符数组
	char[] t1 = s1.toCharArray();
	c1[0] = (char)0;
	for(int i = 1; i < t1.length;  i++)
	{
		c1[i + 1] = t1[i];
	}
	String s2 = "BDCAABA";
	char[] c2 = new char[s2.length() + 1];//带0号字符的字符数组
	char[] t2 = s2.toCharArray();
	c2[0] = (char)0;
	for(int i = 1; i < t2.length;  i++)
	{
		c2[i + 1] = t2[i];
	}
	
	int[][] bak = new int[c1.length][c2.length];
	for(int i = 0; i < c1.length; i++)
	{
		for(int j = 0 ; j < c2.length; j++)
		{
			bak[i][j] = -1;
		}
	}
	System.out.println(lcs(c1,c2,c1.length -1 ,c2.length - 1,bak));
}

}

你可能感兴趣的:(最长公共子序列--求最长公共子串长度)