首页 > 代码库 > 分治法应用----最大子序列和与最大子序列乘积

分治法应用----最大子序列和与最大子序列乘积

分治法,采用一种“分治(divide-and-conquer)”的策略。其想法是把问题分成两个大致相等的子问题,然后递归地对他们求解,这是“分”的含义。“治”阶段将两个子问题修补到一起并外加少量附加工作,最后得到整个问题的答案。分治法的思想其实是递归。

【求最大子序列和】在最大子序列和问题中,最大子序列和可能出现在三处。可能是整个数组的左半部,可能是整个数组的右半部,也有可能是跨越中间元素从而位于左右两部分之间。前面两种情况很容易使用递归来求解,第三种情况可以通过前半部分(包含左半部分最后一个元素)和最大和以及后半部分(包含有半部分第一个元素)最大和,再把二者相加得到。最后三种情况得到的三个值中,最大者就是我们所要的结果。

<span style="font-size:18px;"> public static int maxSum(int[] a,int left,int right) {
			if(left==right)return a[left];
			
			int center=(left+right)/2;
			
			int maxLeftSum=maxSum(a,left,center);
			int maxRightSum=maxSum(a,center+1,right);
			
			int maxLeftBorderSum=0,leftSum=0;
			
			for(int i=center;i>=left;i--)
			{
				leftSum+=a[i];
				if(leftSum>maxLeftBorderSum)
					maxLeftBorderSum=leftSum;
			}
		
			
			int maxRightBorderSum=0,rightSum=0;
			
			for(int i=center+1;i<=right;i++)
			{
				rightSum+=a[i];
				if(rightSum>maxRightBorderSum)
					maxRightBorderSum=rightSum;
			}
			
			return Math.max(maxRightBorderSum+maxLeftBorderSum,Math.max(maxLeftSum,maxRightSum));

		  }</span>

【求最大子序列乘积】

Find the contiguous subarray within an array (containing at least one number) which has the largest product.

For example, given the array [2,3,-2,4],

the contiguous subarray [2,3] has the largest product = 6.

对于求最大子序列乘积问题,思路和最大子序列和问题差不多,不过在第三种情况的求解时,稍微复杂一点。为什么会复杂一点呢?原因是符号问题,所以在求第三种情况时,除了要求解最大乘积,还要求解最小乘积。这个道理是很显然的。

<span style="font-size:18px;"> public static int maxProduct(int[] a) {
		return maxProduct(a,0,a.length-1);
	    }
	  
	 public static int maxProduct(int[] a,int left,int right) {
		if(left==right)return a[left];
		
		int center=(left+right)/2;
		
		int maxLeftProduct=maxProduct(a,left,center);
		int maxRightProduct=maxProduct(a,center+1,right);
		
		int maxLeftBorderProduct=a[center],leftProduct=1;
		
		for(int i=center;i>=left;i--)
		{
			leftProduct*=a[i];
			if(leftProduct>maxLeftBorderProduct)
				maxLeftBorderProduct=leftProduct;
		}
		
       int minLeftBorderProduct=a[center];
       leftProduct=1;
		
		for(int i=center;i>=left;i--)
		{
			leftProduct*=a[i];
			if(leftProduct<minLeftBorderProduct)
				minLeftBorderProduct=leftProduct;
		}
		
		
		int maxRightBorderProduct=a[center+1],rightProduct=1;
		
		for(int i=center+1;i<=right;i++)
		{
			rightProduct*=a[i];
			if(rightProduct>maxRightBorderProduct)
				maxRightBorderProduct=rightProduct;
		}
		
       int minRightBorderProduct=a[center+1];
       rightProduct=1;
		
		for(int i=center+1;i<=right;i++)
		{
			rightProduct*=a[i];
			if(rightProduct<minRightBorderProduct)
				minRightBorderProduct=rightProduct;
		}
		
		int max1=Math.max(maxLeftProduct, maxRightProduct);
		int max2=0;
		if(maxLeftBorderProduct>0&& maxRightBorderProduct>0)max2=maxRightBorderProduct*maxLeftBorderProduct;
		else if(maxLeftBorderProduct<0&& maxRightBorderProduct<0)max2=maxRightBorderProduct*maxLeftBorderProduct;	
		else max2=Math.max(maxRightBorderProduct, minLeftBorderProduct);

		int max3=Integer.MIN_VALUE;
		if(minLeftBorderProduct<0&& minRightBorderProduct<0)max3=minRightBorderProduct*minLeftBorderProduct;	
		
		return Math.max(max1,Math.max(max2, max3));

	  }</span>



分治法应用----最大子序列和与最大子序列乘积