在线处理算法求最大子列和的核心思想:如果整数序列 { a 1 , a 2 , a 3 , … , a n } \{a_1,a_2,a_3,\ldots,a_n\} {a1,a2,a3,…,an}的最大子列和是 { a i , a 1 + 1 , … , a j } \{a_i,a_1+1,\ldots,a_j\} {ai,a1+1,…,aj},那么必定有 ∑ k = i l a k ⩾ 0 \sum_{k=i}^la^k\geqslant0 ∑k=ilak⩾0对任意 i ⩽ l ⩽ j i{\leqslant}l{\leqslant}j i⩽l⩽j成立。这里的最大子列和为正,若序列的全部元素为负数或零,则认为子列和为正。
#include <stdio.h>
int main()
{
int K,MaxSequenceSum=0,tep=0;
scanf("%d",&K);
int Sequence[K];
for(int i=0;i<K;i++)
{
scanf("%d",&Sequence[i]);
}
for(int i=0;i<K;i++)
{
tep+=Sequence[i];
if(tep>MaxSequenceSum)
MaxSequenceSum=tep;
else if(tep<0)
tep=0;
}
printf("%d",MaxSequenceSum);
return 0;
}
我翻了陈越老师的《数据结构》,知道最大子列和的前子列不能为负。
在线处理的代码中,循环时,如果一个子列的和为负,就把这个子列全部抛弃了,再从子列的后半部分开始累加。
为什么可以从子列的后面开始重新求子列?最大的子列会不会包含丢弃的子列的后半部分?这样会不会忽略了一部分子列?
答:
(1)、最大子列不会包含丢弃子列的后半部分。因为丢弃子列的后半部分小于0。
为什么丢弃的子列后半部分一定小于0?
考虑丢弃的子列的元素个数>=2。首元素肯定>=0,而丢弃的子列小于0,故后半部分的子列和小于0,即最大子列和不包含丢弃子列的后半部分。
(2)、
那么还会不会忽略一部分子列呢?
序列若全为负数,则返回零。反之,则存在最大子列,且最大子列是以序列中的某个元素为起始元素。丢弃正数或零开头的负子列,意味着这个丢弃子列的所有元素都不可能是未记录的最大子列的起始元素。以丢弃的第一个子列为例,若丢弃子列的第一个元素是最大子列的起始元素,那么最大子列肯定被记录。假设丢弃子列的非起始元素是最大子列的起始元素,若最大子列的末尾元素超出丢弃子列,则如(1)中所讲,不可能。若最大子列的末尾元素在丢弃子列之内,则这个最大子列加上丢弃子列的前半部分会更大,故最大子列的起始元素不可能在丢弃子列之内。
(表述得很啰嗦,要是举个例子可能会更方便大家理解,但是没想好怎么举例子,而且我有点懒地举例子。总感觉缺少代码对应的数学语言,这样可以方便地用来证明)
PS.为了输入数学公式,下载了mathtype,结果PPT上用mathtype打出的公式复制到博客上是图片。这篇讲markdown的博客挺好的。Markdown系列(6)- 如何优雅地在Markdown中输入数学公式