实现内容: 假如有这样一个数组,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;mmaxSum){ //当前最大子数组和较大时,更换起始元素下标 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; }}