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

最长公共子序列算法应用非常广泛:比如染色体中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的一个最长公共子序列。

递归定义最优解
在这里插入图片描述
自底向上求最长公共子串长度

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));
	}

}

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值