利用分治法求解最大子数组和

一个数组的最大子数组和可能存在于三种情况中:

1. 该数组的左子数组中

2.该数组的右子数组中

3.可能横跨左右子数组

所以,我们可以将问题分解成一个个的子问题,其中情况1和2可用递归求解,而情况3则需要计算

s1=max{} (1 <= i <= n/2), s2=max{} (n/2+1 <= j <=n),其中情况3中s1必然包含了,

s2中必然包含了,因为情况3跨越了左右子数组。s1 + s2为情况3的最大子数组。


/*
 * 利用分治法求最大子数组问题
 */
public class TestOne {

	public static int leftFlag;	//负责记录最大子数组和的开始下标
	public static int rightFlag; //负责记录最大子数组和的结束下标
	
	//求最大子数组跨越了两个数组的情况
	public static int midArray(int[] a,int low,int mid,int high) {
		
		// 求low...mid之间的最大数组和
		int leftSum = -10000;
		int sum = 0;
		for(int i = mid;i>=low;i--)
		{
			sum += a[i];
			if(sum > leftSum)
			{
				leftSum = sum;
				leftFlag = i;
			}
		}
		
		//求mid+1...high之间的最大数组和
		int rightSum = -10000;
		sum = 0;
		for(int i = mid+1;i<=high;i++)
		{
			sum += a[i];
			if(sum > rightSum)
			{
				rightSum = sum;
				rightFlag = i;
			}
		}
		
		return leftSum + rightSum;
	}
	
	public static int subArray(int[] a,int low,int high) {
		if(high==low)
			return a[low];
		int mid = (low + high) / 2;
		int leftSum = subArray(a,low,mid);	//求出左边数组的最大子数组和
		int rightSum = subArray(a,mid+1,high);	//求出右边数组的最大子数组和
		int midSum = midArray(a,low,mid,high);	//求出跨越左右两个数组的最大子数组和
		
		if(leftSum > rightSum && leftSum > midSum)
			return leftSum;
		else if(rightSum > leftSum && rightSum > midSum)
			return rightSum;
		else
			return midSum;
	}
	
	public static void main(String[] args) {
		int[] a = {13,-3,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
		
		System.out.println(subArray(a,0,a.length-1));
		System.out.println(leftFlag + "  " + rightFlag);
	}

}

猜你喜欢

转载自blog.csdn.net/hjl_heart/article/details/80025152