问题描述:
连续子序列最大和,其实就是求一个序列中连续的子序列中元素和最大的那个。
比如例如给定序列:
{ -2, 11, -4, 13, -5, -2 }
其最大连续子序列为{ 11, -4, 13 },最大和为20。
===============================================================
问题分析:
1.首先最朴素的方法是暴力 O(n^3)
直接两个for循环枚举子序列的首尾,然后再来个循环计算序列的和,每次更新和的最大值。
但是这种方法的复杂度是O(n^3),效率实在太低了。。。
————————————————————————————————————————————————
2.第二种方法是预处理 O(n^2)
在读入的时候将前面数的和放在数组中,就能得到一个数组sum[i]储存前i个数的和。然后两重循环枚举首尾,利用sum数组迅速求出子序列的和。
其实这种方法只是优化了前面那种方法的计算和的循环,复杂的是O(n^2),也很糟糕。
————————————————————————————————————————————————
3.第三种是利用分治思想 O(nlogn)
分治算法但看代码不是很好理解,其实思想很简单,就是把序列分成两块计算,用递归分别求出两块序列中的最大子序列和,然后从序列中间向两边遍历求出包含中心的序列的最大和。返回最大的那个序列和。
递归真的很神奇,一直把问题分解乘小问题交给下一层递归处理,直到最底层。
用分治算法的复杂度好了一些,是O(nlogn),虽然不是最优解,但是理解这种算法的确能让我们对递归理解得更加深刻。
————————————————————————————————————————————————
4.第四种是累积遍历算法 O(n)
遍历序列的时候对Sum进行累计,如果Sum累积后小于0的话就把Sum重置为负无穷,每次更新Sum的最大值。最后便能求出最大值。
其实这个算法就是把序列分为好几块,每一块满足:对于任意k,前k个数的和不会小于0(小于0就会分裂成两块了),当前i个数的和大于最大值时就进行更新,而最大值的左边界就是该块序列的第一个,右边界是第i个。
时间复杂度为O(n),而且可以一边读取一边处理,不需要开辟数组来存,空间也很省。