求数组的一个最大子数组

实现内容:
	假如有这样一个数组,A[] = {13,-2,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};要求得到一个总值最大的子数组。例如A[]的一个最大子数组为A[7..10]={18,20,-7,12}。

求解思想:
	1)暴力求解
		循环每一个元素,并从每一个元素的下标开始累加,每次选取较大的和。例如从第一个元素开始,第一次累加是13,那么记录最大的maxSubArray为13;第二次累加为13-2=11,比13小,maxSubArray还是为13;然后继续累加,选择最大的maxSubArray;最后循环下一个元素。A为输入数组,n为最大子数组起始元素下标,m为最大子数组终止元素下标,maxSum为最大子数组的和
	   伪代码:
	   FindMaxSubArray(A)
	   maxSum=0
	   for i = 1 to A.length
	   		let curSum = 0
	   		for j = i to A.length
	   			curSum = curSum + A[j]
	   			if curSum > maxSum
	   				maxSum = curSum
	   				let n = i,m = j
	   return n,m,maxSum
		
	2)分治思想
		分治思想,把一个问题分解为很多小问题,先解决小问题然后再逐级向上解决整个问题。该问题的解决思想跟归并排序类似,先把数组拆分为两个子序列,然后两个子序列继续拆分。同样也需要一个辅助函数,用于计算子序列数组对应下标的最大子数组和。
	   伪代码:
		FindMaxCrossingSubArray(A,low,mid,high)  //辅助函数
		left-sum = -∞
		sum = 0
		for i = mid down to low 
			sum = sum + A[i]
			if sum > left-sum
				left-sum = sum
				max-left = i

		right-sum = -∞
		sum = 0
		for j = mid + 1 to high
			sum = sum + A[j]
			if sum > righ-sum
				right-sum = sum
				max-right = j
		return (max-left,max-right,left-sum+right-sum)

		FindMaxSubArrau(A, low, high) //主函数
		if high == low 
			return (low,high,A[low]) //分解为只有一个元素时
		else
			mid = (low+high)/2
			(left-low,left-high,left-sum) = FindMaxSubArrau(A,low,mid)
			(right-low,right-high,right-sum) = FindMaxSubArrau(A,mid+1,high)
			(cross-low,cross-high,cross-sum) = FindMaxCrossingSubArray(A,low,mid,high)
			if left-sum >= right-sum and left-sum >= cross-sum
				return (left-low,left-high,left-sum)
			else if right-sum >= left-sum and right-sum >= cross-sum
				return (right-low,right-high,right-sum)
			else 
				return (cross-low,cross-high,cross-sum)

	3)最优解
		假如有这样一个数组,数组元素大于2并且数组元素里面有正负,那么最大子数组起始元素一定是正整数,每次从正整数开始计算,求出最大的子数组。i为最大子数组起始元素下标,j为最大子数组终止元素下标,maxSum为最大字数组的和
	   伪代码:
	   	FindMaxSubArray(A)  //注释的代码功能为记录最大子数组起始元素和终止元素的下标
		flag = maxSum = curSum = 0
		//i = j = 0;
		for m = 0 to A.length
			curSum = curSum + A[m]
			if curSum > maxSum
				//if flag != i
				//	i = flag
				//j = m
				maxSum = curSum
			if curSum < 0
				curSum = 0
				//if m < A.length-1
				//	if A[m+1] > 0
				//		flag = m + 1
		//return i,j,maxSum 
		return maxSum

  

class FindMaxSubArray{
	public static void main(String[] args) {
		int[] A= {13,-2,-25,20,-3,-16,-23,18,20,-7,12,-5,-22,15,-4,7};
		//int[] A = {13,-2,-2,10};
		//存放最大字数组的起始下标,终止下标,数组和
		int[] result = new int[3];
		//result = FindMaxSubArray1(A,result);
		//result = FindMaxSubArray2(A,result,0,A.length-1);
		result = FindMaxSubArray3(A,result);
		for (int i: result) {
			System.out.print(i+" ");
		}
	}

	//暴力求解
	public static int[] FindMaxSubArray1(int[] A,int[] result){
		int i = 0, j = 0;
		int maxSum = 0;
		int len = A.length;
		for (int m = 0;m < len; m++) {
			int curSum = 0;
			for (int n = m; n < len; n++) {
				curSum += A[n];
				if (curSum > maxSum){
					maxSum = curSum;
					i = m;
					j = n;
				}
			}
		}
		getResult(result,i,j,maxSum);
		return result;
	}

	//分治思想
	public static int[] FindMaxSubArray2(int[] A,int[] result,int low,int high){
		if(low==high){
			result = getResult(result,low,high,A[low]);
			return result;
		}else{
			int mid = (low+high)/2;
			int[] leftResult = new int[3];
			int[] rightResult = new int[3];
			int[] crossResult = new int[3];
			leftResult = FindMaxSubArray2(A,leftResult,low,mid);
			rightResult = FindMaxSubArray2(A,rightResult,mid+1,high);	
			crossResult = FindMaxCrossingSubArray(A,crossResult,low,mid,high);
			
			if(leftResult[2]>=rightResult[2]&&leftResult[2]>=crossResult[2]){
				result = leftResult;
				// System.out.print("left: ");
				// for(int i:result){
				// 	System.out.print(i+" ");
				// }
			}
			else if (rightResult[2]>=leftResult[2]&&rightResult[2]>=crossResult[2]) {
				result = rightResult;
				//System.out.print("right: ");
				// for(int i:result){
				// 	System.out.print(i+" ");
				// }
			}else{
				result = crossResult;
				// System.out.print("cross: ");
				// for(int i:result){
				// 	System.out.print(i+" ");
				// }
			}
			//System.out.println();
			return result;
		}
	}

	//分治过程中用到的辅助函数
	public static int[] FindMaxCrossingSubArray(int[] A,int[] result,int low,int mid,int high){
		int leftSum = A[mid];
		int curLeftSum = 0;
		int left = mid;
		for(int i = mid; i >= low; i--){
			curLeftSum += A[i];
			if(curLeftSum > leftSum){
				leftSum = curLeftSum;
				left = i;
			}
		}

		int rightSum = A[mid+1];
		int curRightSum = 0;
		int right = mid+1;
		for(int i = mid+1; i <= high; i++){
			curRightSum += A[i];
			if(curRightSum > rightSum){
				rightSum = curRightSum;
				right = i;
			}
		}
		result = getResult(result,left,right,leftSum+rightSum);
		return result;
	}

	//最优解
	public static int[] FindMaxSubArray3(int[] A,int[] result){
		int m;
		int i = 0;//记录起始元素的下标
		int j = 0;//记录终止元素的下标

		/*//记录 上一次maxSum最大时终止元素的下标
		int k = 0;*/
	
		int flag = 0;//记录curSum又一次从负整数变为正整数时起始元素的下标
		int maxSum = 0;//最大子数组和
		int curSum = 0;//当前最大子数组和
		for (m=0;m<A.length ;m++ ) {
			curSum += A[m];
			if(curSum>maxSum){
				//当前最大子数组和较大时,更换起始元素下标
				if (flag != i) {
					i = flag;
				}
				j = m;//更换当前终止元素下标
				maxSum = curSum;

				//更换上一次最大子数组终止元素的下标
				/*if(k!=0||k!=j){
					k++;
				}
				if ((j-k)!=1||j==0){
					k = m;
				}*/
				
			}
			if(curSum<0){
				curSum = 0;
				//记录下一个正整数为起始元素的下标
				if (m<(A.length-1)) {
					if (A[m+1]>0) {
						flag = m+1;
					}
				}
			}
		}
		result = getResult(result,i,j,maxSum);
		return result;
	}

	public static int[] getResult(int[] result,int i,int j,int maxSum){
		result[0] = i;
		result[1] = j;
		result[2] = maxSum;
		return result;
	}
}

  

原文地址:https://www.cnblogs.com/yzdtofly/p/7273473.html