对于一个数组,尽可能地划分成两半(二分),加和最大的连续字数组或者在左边,或者在右边,或者跨越中间,一部分在左边,一部分在右边。
那么只要求出左半段数组的加和最大的连续子数组的和,求出右半段数组的加和最大的连续子数组的和,求出跨越中间的最大连续字数组的和,只要通过三者判断求出最大的那么就是整个数组最大的连续子数组的和。
那么找出左半段和右半段的最大连续子数组的和其实就是比原问题规模更小的一个问题,因此对于左半段和右半段求解加和最大的连续子数组的和可以通过递归求得。
下面给出具体实现:、
首先是调用接口:
1 /** 2 * 该函数是找出数组中连续子数组的最大和(连续的数组段 3 * -1,3,-2 , 4 ,5,10,-1那么数组的连续子数组的和的最大值就是20,[3,-2 , 4 ,5,10] 4 * 为所求 5 * 想法:对一个数组划分为尽可能相等的两段(二分),加和最大的一段或者在左边 6 * 或者在右边,或者是跨中间的,那么我们只需要找出左边最大的子数组的和和右边最大的子数组的和 7 * 最后找出跨中间最大的子数组的和,然后在这三个子数组中和最大的一个肯定就是整个数组中是最大 8 * 那么对于左边数组求最大和其实就是原问题的子问题,也是对左边数组进行划分成两半,然后对于左边 9 * 数组分析和原来分析一样,也是可能最左边,或者在右边,或者在中间,因此一直递归即可找到连续10 * 子数组的最大加和11 * @param array 12 * @return13 * @throws Exception 14 */15 public static int findSumMax(int[] array){16 if (array == null) {17 throw new NullPointerException("数组空指针异常");18 }else if (array.length == 0) {19 return 0;20 }else {21 return findMaxFromLeftMiddleRight(array, 0, array.length - 1);22 }23 }
然后就是对数组分段之后求左右段和跨中间段的加和最大的连续子数组的和,然后进行比较,求出最大的就是整个数组最大的连续子数组的最大和
1 /** 2 * 找出左半段,右半段,中间段的最大值 3 * @param array 4 * @param left 5 * @param right 6 * @return 7 */ 8 private static int findMaxFromLeftMiddleRight(int[] array , int left , int right){ 9 if (left == right) {10 return array[left] > 0 ? array[left] : 0;11 }12 int middle = (left + right) / 2;13 //找出左边的最大值14 int maxL = findMaxFromLeftMiddleRight(array, left, middle);15 //找出右边的最大值16 int maxR = findMaxFromLeftMiddleRight(array, middle + 1, right);17 //找出跨越中间的最大值18 int maxMid = findMaxCrossMiddle(array, left, right);19 return (maxL > maxR ? maxL : maxR) > maxMid 20 ? (maxL > maxR ? maxL : maxR) : maxMid;21 }
最后的重点就是找出跨越分界的两端的连续子数组的最大加和
1 /** 2 * 找出跨越中间的数组的最大连续子数组的最大加和 3 * 想法:找出中间的位置,从左边一段的最右开始往回找,直到找到最大值 4 * 再从右边一段的最左往右找,直到找到最大值,然后两个和加起来就是跨 5 * 越中间的连续子数组的最大值 6 * @param array 7 * @param left 8 * @param right 9 * @return10 */11 private static int findMaxCrossMiddle(int[] array , int left , int right){12 if (left == right) {13 return array[left] > 0 ? array[left] : 0;14 }15 //尽可能找出数组中间16 int mid = (left + right) / 2;17 int maxL = 0;18 //sum用于记录左半段数组的加和19 int sumL = 0;20 //从中间往左边找,找到最大值21 for (int i = mid; i >= left; i--) {22 //一旦左半边的加和比已缓存的左边最大值大,那么就更新最大值23 if ((sumL = sumL + array[i])> maxL) {24 maxL = sumL;25 }26 }27 int maxR = 0;28 int sumR = 0;29 //从中间往右边找,找到最大值30 for (int j = mid + 1; j <= right; j++) {31 if ((sumR = sumR + array[j]) > maxR) {32 maxR = sumR;33 }34 }35 return (maxL+maxR);36 }
1 //测试程序如下2 public static void main(String[] args) {3 int[] array = {-1,3,-2 , 4 , 5,10,-1 , 6,-4,3,-8};4 System.out.println(MyUtil.findSumMax(array));5 }
可求得测试结果为25。