求数组的子数组之和的最大值

明确题意:

  1. 子数组是连续的
  2. 只需要求和,不需要返回子数组的具体位置
  3. 元素是整数,数组可能包含正整数、零、负整数

举例子:

数组 [1, -2, 3, 5, -3, 2] 应返回: 8

 

明确题意


  起初我想的是即使是循环,也不能解决这个问题,比如以上例子中元素3,5组成“最大”子数组。更何况如果3和5距离很远。当然后者加剧了题目的复杂度。

所以,第一步,明确“题”意是求解很重要的一环。

 

示例代码1:

int maxSum(int* A, int n)
{
    int maximum =  -1;
    int sum;

    for (int i = 0; i < n; ++i){
        sum = 0;
        for (int j = i; j < n; ++j){
            sum += A[j];
            if (sum > maximum){
                maximum = sum;
            }
        }
    }

    return maximum;
}

但是通过以上O(n^2)复杂度的算法,确实得出题目的解。

实际上这里面是隐含着我所考虑的情况,而且是全部。所要求的是一个连续的子数组的和。那么所有的情况可以分类:

针对1个元素,(a)组成的数组,那么肯定只能是它本身;
针对2个元素,(a,b)组成的数组,除了第一种情况之外,那么就是唯一的一个组合,(第一个元素,第二个元素),即(a,b)
针对3个元素,(a,b,c)组成的数组,也可以罗列出来,如:a或b或c,组合有(a,b) 或 (b,c)(其中ac不满足连续的要求)
针对4个元素,(以此类推)

 

 以上是一个类似小学数学教育当中经常用到的不完全归纳法,通过这种分析,可以得出一种结果,就是,最大子数组的可以按一种标准分类,那就是子数组元素的个数。再加上一个额外的限制条件连续,就可以使用两个循环来解决问题。对于n个元素组成的数组:

123 ,... ,n)

 

设连续的子数组情况有m种(数学不好,凑合着表示):

m = cn1 + (cn2 - 不连续的) + (cn3 - 不连续的) + ... +  (cnn-不连续的)

 

 


 

回过头来再看 示例代码1,内外两层循环上来看,的确是覆盖了以上所有的组合情况。

以数组下表来表示:

maximum来保存最大的子数组和,sum保存某一种子数组的元素组合情况。以下分别用数组元素下标来表示元素的值:

当i=0的时候,sum分别来表示 00+1, (0+1)+2, (01+2)+ 3  , ... , (0+1+2+3+ ... + n-1) + n

当i=1的时候,sum分别来表示 11+2, (1+2)+ 3  , ... , (1+2+3+ ... + n-1) + n
... 当i=n-1的时候,sum分别来表示 n-
1, n-1 + n 当i=n的时候,sum分别来表示 n

 

以上的组合均是连续的。

对于文章开头的例子,最大子数组(3,5)中元素在原来数组中的下表分别是(2,3),即当n=5,i=2,j=3的时候便得到了最大值8

在合适的地方打上适当的输出语句用以观察整个运算情况:

i    j    sum    maximum
0    0    1    1
0    1    -1    1
0    2    2    2
0    3    7    7
0    4    4    7
0    5    6    7

1    1    -2    7
1    2    1    7
1    3    6    7
1    4    3    7
1    5    5    7

2    2    3    7
2    3    8    8
2    4    5    8
2    5    7    8

3    3    5    8
3    4    2    8
3    5    4    8

4    4    -3    8
4    5    -1    8

5    5    2    8

 

 

分治


 每个问题都可以分解成为两个问题规模减半的子问题,再加上一次遍历算法。

 

int max(int x, int y){
    return (x > y) ? x : y;
}

int maxSum_demo2(int* A,int n){
    int nStart = A[n-1];
    int nAll = A[n-1];
    for (int i = n-2; i >= 0; --i)
    {
        nStart = max(A[i], nStart + A[i]);
        nAll = max(nStart, nAll);
    }
    return nAll;
}

 

同样地,在合适的地方打印出结果:

i    A[i]    nStart    nAll
4    -3       -1        2
3    5        5        5
2    3        8        8
1    -2       6        8
0    1        7        8

 

 

 动态规划,分治待看。

 

posted on 2015-05-25 01:08  dotdog  阅读(1055)  评论(0编辑  收藏  举报

导航