求一个长度为n的数组A {A0, A1...An-1}的最大子段和。

为了避免没有意义的容错,我们认为n > 0 且子段长度 > 0。

任意0≤ i ≤ j≤n的下角标组合就可以确定一个子段,也就确定了一个和,一共有1+2+...+n = (n+1)*n/2个和。

设一个子段(闭区间)的累加和为sum(i,j)

sum(i, j)=Ai+...+ Aj

我们按照区间结尾分组,第 i 组有 i+1 行

0 ... k k+1 ...
sum(0,0) ... sum(0,k) sum(0,k+1)=sum(0,k)+Ak+1 ...
  ... sum(1,k) sum(1,k+1)=sum(1,k)+Ak+1 ...
  ... ... ... ...
    sum(k,k) sum(k,k+1)=sum(k,k)+Ak+1 ...
      sum(k+1,k+1)=Ak+1 ...

上表可以表示所有的sum,我们求最大的。

假设我们已知第k 组(以k 结尾的区间)sum的最大值,设为result(k),不需要知道具体是哪一个区间累加出来的。

第k+1组黄色部分,前面每一个值都是第k组对应值加上Ak+1。一个数组,每个数都加上同一个数,最大的那个还是最大的那个.

第k组的最大值是result(k),那第k+1组黄色部分的最大值就是result(k)+Ak+1。常数时间O(1)就能得出。

最后一行也是常数时间得出,所以整组的最大值就是max{ result(k)+Ak+1 , Ak+1 }

Ak+1  要不要加上result(k)就看正负就行了,所以就是result(k+1) = result(k) < 0 ? Ak+1  : result(k) + Ak+1

result(0)=sum(0,0)=A0  也是常数时间得出。由result(0),常数时间可以得出result(1)=result(0) < 0 ? A1  : result(0) + A1,以此类推。

O(n)的时间就能得出所有组的最大值,再从这些最大值里取最大的那个就可以了。

下面附上C语言代码。

1 int max_sum(int[] a, int n) {
2     int result=a[0], group_result=a[0];
3     for(int i=1; i<n; i++) {
4         group_result = group_result  < 0 ? a[i] : group_result + a[i];
5         if(group_result > result)
6             result = group_result ;
7     }
8     return result;
9 }