三种算法求解一个数组的子数组最大和

 

前阵子去淘宝的暑期实习生去笔试,遇到这样一个题:要求一个数组连续下标和的最大值,数组的元素可正、可负、可为零,例如-253-64-86将返回8

 

这题嘛,是很经典的一道公司的笔试或者面试题了,也有各种解法,从算法分析上,时间复杂度也有很大差别,下面我就给出三种不同的解法,看完之后,你应该就知道如果你面试的时候遇到这样的题,你应该用哪种方法最能让考官满意。

 

方法一:暴力枚举法

此种方法最简单,我想应该也是每个人拿到题目想到的第一种解法了,学过一点编程的人都应该能编出此类程序。

sum[i..j]为数组中第i个元素到第j个元素的和(其中0<=i<j<=n-1),通过遍历所有的组合之和,就能找到最大的一个和了。

伪代码如下:

此种方法的时间复杂度为O(n2),显然不是一种很好的办法,也不是公司面试希望你写出这样的程序的。

 

       方法二:分支界定

       这里再介绍一种更高效的算法,时间复杂度为O(nlogn)。这是个分治的思想,解决复杂问题我们经常使用的一种思维方法——分而治之。

       而对于此题,我们把数组A[1..n]分成两个相等大小的块:A[1..n/2]A[n/2+1..n],最大的子数组只可能出现在三种情况:

  • A[1..n]的最大子数组和A[1..n/2]最大子数组相同;

  • A[1..n]的最大子数组和A[n/2+1..n]最大子数组相同;

  • A[1..n]的最大子数组跨过A[1..n/2]A[n/2+1..n]

       前两种情况的求法和整体的求法是一样的,因此递归求得。

       第三种,我们可以采取的方法也比较简单,沿着第n/2向左搜索,直到左边界,找到最大的和maxleft,以及沿着第n/2+1向右搜索找到最大和maxright,那么总的最大和就是maxleft+maxright

       而数组A的最大子数组和就是这三种情况中最大的一个。

       伪代码如下:

 

    方法三:动态规划

       这算是一个经典的动态规划的题目了,如果不知道动态规划可以先不去理解这个名词。用通俗点的语言描述这个算法就是:

cursum(i)表示数组下标以i为起点的最大连续下标最大的和,而maxsum(i)表示前i个元素的最大子数组之和。那么我们就可以推出下一个maxsum(i+1)应该为cursum(i+1)maxsum(i)中选取一个最大值。递推式为:

cursum(i) = max{A[i],cursum(i-1)+A[i]};

maxsum(i) = max{maxsum(i-1),cursum(i+1)};

伪代码为:

 

这种算法时间复杂度只是O(n),效果非常好!我想如果笔试的时候能完整的写出这种算法,应该堪称perfect了!而是面试,你可以通过比较这三种算法,可以很明显为你的表现加分的,因为算法设计分析能力是这个专业所必备的一项基本的素质!

 

 

     

 参考文献: 编程之美   电子工业出版社

 源代码下载地址:http://download.csdn.net/source/3258272


版权申明:版权所有,翻版不究!欢迎学习交流。如发现BUG,恳请批评指正!

 

posted @ 2011-05-08 01:02  hazir  阅读(676)  评论(0编辑  收藏  举报

一个代码可以创造一个世界,也可以毁灭一个世界!