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

刚才看见了一个很有意思的帖子,讲《编程之美》里的一道题目,和相关延伸,觉得不错,就都总结下来吧。

 

一个有N个整数元素的一维数组(A[0],A[1],...A[n-2],A[n-1]),求这个数组的子数组之和的最大值?

 

假设已经知道(A[1],...A[n-1])中和最大的一段之和为All[1],并且已经知道(A[1],...A[n-1])中包含A[1]的和最大的一段的和为Start[1]。那么,(A[0],...A[n-1])中问题的解All[0]为max{A[0],A[0]+Start[1],All[1]}

所以,得到程序如下:

 1 int MaxSum(int A[], int n)
 2 {
 3     nStart = A[n-1];
 4     nAll = A[n-1];
 5     for(i=n-2;i>=0;i--)
 6     {
 7        if(nStart<0)
 8            nStart=0;
 9        nStart += A[i];
10        if(nStart>nAll)
11            nAll=nStart;
12     }
13     return  nAll;
14 }

 

时间复杂度仅为O(n)

 

 现在有人将这个题目变了一下型:

同样有一个N个元素的一维数组,要求出不连续子数组和的最大值,不连续的意思,就是子数组中的任意相邻元素,在原数组都不能相邻。

假设从原数组a第i位开始的最大不连续子数组和为m[ i ],那么它的值有两种可能,一种是当前元素a[ i ]与隔一位上子问题解m[ i+2 ]之和(由不连续性质决定),另一种是不包含当前元素而直接等于前一位上子问题解m[ i+1 ],那么我们可以写出递推公式为:m[ i ] = max(a[ i ] + m[ i+2 ], m[ i+1 ])。

如果m[i+1]不包括a[i+1],则其值相当于m[i+2];所以m[ i ] = max(a[ i ] + m[ i+2 ], m[ i+1 ])无误。

 程序如下:

 1 int maxsum(int* a, int n)
 2 {
 3     int m2 = 0;
 4     int m1 = a[ n-1 ];
 5     for(int i = n - 2; i >= 0; i--)
 6     {
 7         if(m2 < 0) m2 = 0;  //处理最后一位为负数或全为负数的情况
 8         int tmp = m1;
 9         m1 = max(a[ i ] + m2, m1);
10         m2 = tmp;
11     }
12     return m1;
13 }

 

 

 

posted on 2009-06-29 12:37  nanduo  阅读(503)  评论(0)    收藏  举报