分治策略求解数组的最大连续子数组的和

对于一个数组,尽可能地划分成两半(二分),加和最大的连续字数组或者在左边,或者在右边,或者跨越中间,一部分在左边,一部分在右边。

那么只要求出左半段数组的加和最大的连续子数组的和,求出右半段数组的加和最大的连续子数组的和,求出跨越中间的最大连续字数组的和,只要通过三者判断求出最大的那么就是整个数组最大的连续子数组的和。

那么找出左半段和右半段的最大连续子数组的和其实就是比原问题规模更小的一个问题,因此对于左半段和右半段求解加和最大的连续子数组的和可以通过递归求得。

下面给出具体实现:、

首先是调用接口:

 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      * @return
13      * @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      * @return
10      */
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。

时间: 2024-10-20 16:27:20

分治策略求解数组的最大连续子数组的和的相关文章

求数组中任何连续子数组的最大和,并打印最大子数组(求开始和结束下标)

//计算数组中任何连续子数组的最大和,并打印最大子数组(求开始和结束下标) //思路:1:当数组元素全为0时,输出最大的那个负数 //      2:当数组有正有负时,i=0遍历数组,从大于0的那个元素开始,记录此时的下标为shart(最大子数组起始下标),从start开始遍历剩下的元素,若元素和num大于max的值则更新max, //    且将此时的下标赋值给end(最大子数组终止下标),当num小于0则说明后面出现的(如果出现)最大子数组不可能包含这些元素,所以退出内层循环,继续外层循环,

最大子数组问题(求连续子数组的最大和)

在<算法导论>第四章分治策略(Divider and Conquer)4.1节提出了最大子数组问题.其转化就是求数组a={1, -2, 3, 10, -4, 7 , 2, -5}中连续子数组的最大和. 对于这个问题,很容想到一种暴力求解的方法:简单地尝试对所有可能的的组合进行求和.对数组为n存在n*(n-1)/2中组合,然后对每个组合进行求和.即三个for循环遍历,求出数组中每一个子数组的和,最终求出这些子数组的最大的一个值.记Sum[i,...,j]为数组a中第i个元素到第j个元素的和(其中

求一个整数数组的最大连续子数组的和

输入一个整数数组,数组里有正数也有负数. 数组中连续的一个或多个整数组成一个子数组,每个子数组都有一个和. 求所有子数组的和的最大值. int max(int a,int b) { if(a>b) { return a; } else { return b; } } int maxsum(int a[], int n) { int i; int maxsofar = 0; int maxendinghere = 0; for (i = 0; i < n; i++) { maxendingher

一个有N个整数元素的一维数组{A[0],A[1],....,A[N-1],A[N]},这个数组有很多连续的子数组,那么连续子数组之和的最大的一个的值是什么?

1.动态规划的思想解决 /** * 在时间复杂度为O(N)内找出数组中最大的子序列的累加和 */ public static int sumNum(int[] array) { int n = array.length; int all = array[n - 1], start = array[n - 1]; int count = 0; for (int i = n - 2; i >= 0; i--) { if ((start + array[i]) > array[i]) { start

求数组中连续子数组的最大和

问题: 求解数组中连续一段子数组和的最大值.例如:{31,-41,59,26,-53,58,97,-93,-23,84},最大值为59+26-53+58+97=187 思路: 计算出任意i到j之间连续子数组的和再比较必然能得到最大值,但时间复杂度为O(n^2),我们希望能找出线性时间的算法. 我们注意到,假如数组中全为正数,那么最大和必然为全部数相加:如果数组中有负数,并且如果加上某个负数,子数组的和小于0,则最大和子数组必然不包含这个负数. 基于此,给出以下代码: //计算数组中任何连续子数组

[算法导论]4.1-5最大连续子数组问题

在线性时间内非递归的求数组的最大连续子数组(连续和最大的子数组). 题目给出思路为数组A[1...j+1]的最大和子数组,有两种情况:a) A[1...j]的最大和子数组; b) 某个A[i...j+1]的最大和子数组,但思考很久没有理解如何用这个思路设计线性时间算法,希望有人能给予指点. (i点是使A[1]+..+A[i]为负的一个值?) 目前的思路是,最大子数组一定位于从某个正数开始,全部求和<=0的一段数组中 从其实点i到目标点j,从第一个正数开始截取尽量长的一段数组,从第一个正数起的最大

《返回一个二维整数数组中最大联通子数组的和》

设计思想:(1)首先把这个二维数组按行的数目分解为与列数目具有相同数目的一维数组: (2)再分别求出这几个一维数组的最大连续子数组之和,分别记录每一个最大连续数组的首末位置: (3)接着分别比较看这几个一维数组的首末位置是否处于矩阵上相连的位置,找出位置上相连且之和为最大的数组,输出它们的和即可. 源代码: #include<iostream> using namespace std; int Max(int n,int a[],int *smark,int *mmark) { int b[1

最大子矩阵,最大连续子数组进阶,动态规划初级,poj1050

题目描述:现给出一个N*N矩阵,要求求出拥有最大和的子矩阵的和. 例如: 这样的一个矩阵,最大子矩阵的和为15: 此题可以让人联想到求最大连续子数组,求最大子数组在上一篇文章中http://www.cnblogs.com/tz346125264/p/7560708.html. 分析:最大子矩阵可以看为求最大连续子数组拓展到二维数组上,因为矩阵的性质同样在横向竖向上需要连续,那么可以想办法将这个二维数组简化为求连续子数组. 思考: 1.要求最大子矩阵,必须保证每个矩阵都被浏览到,为了保证运行时间尽

[算法导论]练习4.1-5最大连续子数组问题

题目:在线性时间内非递归的求数组的最大连续子数组(连续和最大的子数组). 思路:设最大子数组的和为max,起点和终点位置为s.e,正在扫描的子数组的和为add,起点和终点位置为i.j.max的初始值为-∞. 1.若数组的值全为负,则返回最大值. 2.逐个扫描数组元素,更新add.i.j的值. a.若add的值为正,则和max的值比较,如果大于max的值,更新max.s.e的值为add.i.j. b.若add的值为负,则从i到j这一段的数字只能减少子数组的和,要丢弃,add值清零并重下一个元素重新