一. 最大子序列和-联机算法
在前两篇博文中,我们了解了两种较差算法,和一种分治算法。下面我们讲解一个更好的方法:联机算法。这种算法的时间复杂度是 O(n)。这个方法也是解决这个问题的最好算法,因为无论如何,读取数据也要 n 次。
1. 实例分析
给定一组数据,data = (1, 4, -3, 7, -6, 10 )。
(1)读取第一个元素 1,此时部分和为 1,大于 0, 说明此元素可以为最大值作出贡献,于是将其加入到子序列中。
(2)接着读入第二个元素 4, 发现这个元素加上部分和等于 5, 大于 0 ,它也能够为最大值作出贡献,将其加入到子序列中。
(3)接着读入第三个元素 -3, 我们发现这个元素是负的,但是它加上部分和等于 2, 大于 0 。虽然它拖了后腿,但是也不至于让部分和成为负的,因此也将其加入到子序列中。
其余元素同理。
我们考虑一个问题:假如读取了一个新元素,这个元素使得部分和小于 0 了,那么应该怎么处理?一个小于 0 的部分和,只会给我们的最大和拖后腿,却不能提供任何有价值的东西。到这一步,我们将部分和重置为 0 ,说明前面的元素前功尽弃了,我们要从它的下一个元素开始,重新计算部分和,看看其余子序列会创造新记录。如果到结尾,所有元素均已处理完毕,有了新的最大和,那么我们将最大和更新,否则最大和不变。
2. 代码实现
1 int max_sub_sum_online(const vector<int>& data) { 2 const int MIN = numeric_limits<int>::min(); 3 int max_sum = MIN, partial_sum = 0; 4 5 for (int i = 0; i < data.size(); ++i) { 6 partial_sum = max(partial_sum, 0) + data[i]; 7 max_sum = max(partial_sum, max_sum); 8 } 9 10 return max_sum; 11 }
代码中没有什么难点。这说明了一个思想:真正好的方法,能够优雅的解决问题,不论是代码实现,还是算法思路,都很容易懂。