现在的位置: 首页 > 综合 > 正文

最长公共子序列和的 算法

2018年04月26日 ⁄ 综合 ⁄ 共 1458字 ⁄ 字号 评论关闭

      对于公共子序列和的求法,我们在学习算法的时候都知道基本的有四种,他们的时间复杂度分别为:O(N^3)   /    O(N^2)   /   O(N logN)    /   O(N)  ,对于前面的两种都是for循环的嵌套,时间用的太多,很不实用,这里就不再写了。只写后面的两种,就当是练手了~

第一种: 递归法(分治)

         把现有的子序列分两段,那么它的最长子序列和的产生只能发生于三种情况: (1)在左半部分产生;(2)在右半部分产生;(3)两半部分的和相加得到  。 如 1 -4 3  -1  2 6 -3 4,分段后左边的最大和为:3,右边的最大和为:9,此时他们的整体最大和就由两部分的和构成,为11。

代码:

private static int maxSumRec(int [] a,int left,int right)
	{
		if(left==right)  // 在临界点时,如果数组中的值是小于0的,直接舍掉,如果是正值就直接加上;
			if(a[left]>0)
			    return a[left];  
		    else
			    return 0;
		// 在没有到达基点是做下面的递归运算;
		// 对两边分别做的递归处理;
		int center=(right+left)/2;
		int maxLeftSum=maxSumRec(a,left,center);  // 开始进入递归运算;
		int maxRightSum=maxSumRec(a,center+1,right);
	    
		// 对左右两边和的最大值的处理;
		int maxLeftBorderSum=0,leftBorderSum=0;
		for(int i=center;i>=left;i--) // 从中间向左一直做加运算,求得包含中间左端向左的最大和子序列的和;
		{
			leftBorderSum+=a[i]; 
			if(leftBorderSum>maxLeftBorderSum)
			    maxLeftBorderSum=leftBorderSum;
		}
		
		int maxRightBorderSum=0,rightBorderSum=0;
		for(int i=center+1;i<=right;i++)
		{
			rightBorderSum+=a[i];
			if(rightBorderSum>maxRightBorderSum)
				maxRightBorderSum=rightBorderSum;
		}
		
		return max3(maxLeftSum,maxRightSum,maxLeftBorderSum+maxRightSum);
	 }
	
	public static int maxSubSum3(int []a)
	{
		return maxSumRec(a,0,a.length-1);
	}
	
	public static int max3(int a,int b,int c)
	{
		return a>(b>c?b:c)?a:(b>c?b:c); // 返回三个数中最大的那个;
	}

第二种: 动态规划法

代码:  局部最优解构成整体最优解;

public static int maxSumRec(int []a)
	{
		int maxSum=0,thisSum=0;  // maxSum 是要求的最大公共子序列的值;thisSum 是当前得到的序列的和;
		for(int j=0;j<a.length;j++)
		{
			thisSum+=a[j]; // 对当前的thisSum更新;
			if(thisSum>maxSum)
				maxSum=thisSum;  //对当前的maxSum更新;
			else if(thisSum<0)
				thisSum=0;
		}
		return maxSum;
	}

上面的只是本人的学习笔记,错误不可避免,欢迎大家指正!

抱歉!评论已关闭.