算法导论里详细说了用时O(nlgn)的算法,主要思路是:
这个序列必定在——左半部分,右半部分,跨越中间的元素的一段序列。
使用的是分治思想,不过左右段搜索可是用了n的时间啊。
这里课后题阐述要给出一个O(n)的算法,显然,对于这个提示:
你只能扫描!
而且也就几次扫描!
否则就不是n的时间了。
我们这么来考虑:
一个数组序列的数字有正有负,最大子序列的最小值至少是0(全是负值,但我们选择了0个元素的子序列),
所以我们有一个初始“最大序列和”:max_sum=0,
显而易见的是我们要一个临时求和变量temp_sum来记录,一旦大于max_sum了,那就赋值给max_sum;
重头戏来了:对于一个刚好求和完毕使得temp_sum小于0的迭代来说,我们要给temp值赋值为0!
可以这样想:
如果刚好让其大于等于0,那等等看,万一后边那个让temp变得更大了呢?
但是如果小于0就算了, 就算加了后面元素,这个temp值也是拖累(减小子序列和大小)
所以直接重新从后面部分开始估计。
不过没关系,已经不要的这一段序列最大和已经被max值保存了。
因此这个函数极为简洁:
def find_max_subarray(arr):
max_sum,temp_sum=0,0
for x in arr:
temp_sum+=x
if temp_sum>max_sum:
max_sum=temp_sum
if temp_sum<0:
temp_sum=0
return max_sum
很显然,一遍遍历,仅需要n次迭代。估计是最快的方法了。
这个应用很广,比如给了每天产品价格要求出哪天买入、卖出收益最大。
那就要初始化一个序列来记录变化量,比如[3,5,2,7]
那么变化量就是[2,-3,5](后面元素减去前面的)
然后我们要求出最大子序列和(的范围)便是最大的收益。