看到数据结构与算法分析(c语言描述)第二章,关于子序列之和的O(n)阶算法,有点难理解,书里面也没有讲明白。网上看了2~3篇博客,总算有点明白了,自己整理一下,以便以后再遇到类似问题的时候可以翻出来看看快速理解。
书上源码:
int MaxSubsequenceSum(const int A[],int N)
{
int ThisSum,MaxSum,j;
ThisSum=MaxSum=0;
for(j=0;j<N;j++)
{
ThisSum+=A[j];
if(ThisSum>MaxSum)
MaxSum=ThisSum;
elseif(ThisSum<0)
ThisSum=0;
}
return MaxSum;
}
关于这段源码,主要有两个问题需要理解:
1.最大子序列和为什么可以是:对数组元素一直累加过程中的最大值
A[0]>0,A[0]+A[1]>0,A[0]+A[1]+ A[2]>0,,,,,,A[0]+A[1]+........+A[p-1]>0。但是A[0]+A[1]+........+ A[p-1]+ A[p]<0。说明 p这个位置,是A数组的元素累加和过程中遇到的第一个小于零的位置。
那么对于在区间[0,p-1]的任意位置k,由于A[0]+ A[1]........A[s]>0 ( s∈(0,k] )且A[0]+ A[1]........A[p]<0,可以给出结论:A[0]+A[1]+........+A[k]>A[s]+........+ A[k]:既0~k位置的元素累加和大于任意s~k位置的子序列之和(图1)。
因为s和k的位置具有在区间[0,p-1]之间的任意性,因此对数组A顺序累加这个过程其实已经遍历了0~p-1之间的所有的子序列的和(注意是子序列的和,并没有遍历0~p-1之间所有子序列),然后if(ThisSum>MaxSum) MaxSum=ThisSum;该语句已经在这个过程中记录了0~p-1之间的所有的子序列的和的最大值。
图1
2.为什么当数组累加和小于零时,可以在当前位置的下一个位置,即A[p+1]的位置重新累加
elseif(ThisSum<0) ThisSum=0;语句说明,当元素累加时遇到第一个位置p,使得A[0]+A[1]+........+ A[p-1]+ A[p]<0时,可以从p+1的位置开始,重新开始这个累加过程。为什么可以这样呢?
此时所有的子序列可以认为分成3种情况:
第1种情况是p之前所有的子序列(既0~p-1之间的所有子序列,已由前面求得0~p-1之间最大子序列的和,存在MaxSum中)。
第2种情况是p之后所有的所有子序列(暂时还未求得)。
第3种情况是包含p这个位置的子序列。
先来考虑一下第3种情况下的子序列:这个子序列的是:
A[m]+........ A[p-1]+ A[p]+ A[p+1]+ ........+ A[n],其中m∈[0,p-1],n∈[p+1,N-1]。
由于A[0]+ A[1]........A[m-1]>0,A[0]+ A[1]........A[p]<0,则说明A[m]+........ A[p-1]+ A[p]<0,见图2。所以p位置之后的子序列A[p+1]+........+ A[n]只要带上p+1之前的子序列A[m]+........ A[p-1]+ A[p],就会变得更小了。因此舍去m~p位置的子序列,可以从p+1位置处重新开始累加A[p+1]+........+ A[n], n∈[p+1,N-1]。这就回到了上述第2种情况的子序列,因此这时只需要计算p之后所有的所有子序列之和的最大值。
图2