经典面试题 之 子数组之和最大值

因为最近要开始笔试和面试了,我觉得,很有必要做好准备~

这个问题是我在网上看到的,13年一家公司的笔试题,求子数组的最大和。这个题我之前在微软的编程之美看到过,不过当时记得并不是很深刻。

现在既然看到了,我就好好的想了想。考试题如下:

上面只给了两行代码的空间,也就是说,只需要两行的代码即可。

对于这个问题,有种很简单,但是效率最低的方法,就是枚举出全部的子数组,并且求和,比较出最大值。我当初写的代码就是这个版本的,现在应该在实验室的电脑里。

但是,在《编程之美》中,对于这个问题提供了三种解法,而且其中的第三种是效率最高的。时间复杂度O(n),空间复杂度为O(1)。

其实可以考虑一种比较极端的情况,就是,只有两个数,A[0] and A[1]。

这样,最大值存在的情况,无非就是:A[0], A[0] + A[1], A[1]。

这个过程基本就是三个数字中,找到最大值的过程。

然后推广到n的时候,从0->n - 1遍历只要重复这个过程,就能简单的获取到最终的最大值。

那么如何推广?

假设现在有三个数字A[3]:A[0] A[1] A[2].

这样先比较前两个元素,A[0],A[1],以及A[0] + A[1]。因为下次的比较需要将前面的A[0]+A[1]作为一个整体加入到下一次的比较中,所以需要有一个值能够用来表示其和。这个变量就是上面的nStart。

nAll则是相当于每次比较中的A[0]。那么每次的比较的顺序就是:A[1]和A[0] + A[1]比较。nStart取其最大值,然后在和相当于A[0]的nAll比较。如此往复,当线性遍历结束的时候,就成功的获取到了最大值。

这个方法相当巧妙,其中很多的细节都要自己慢慢的体会。

程序演示截图:

 

程序代码:

 1 #include <iostream>
 2 
 3 using namespace std;
 4 #define max(a, b) (a) > (b) ? (a) : (b)
 5 int MaxSubArray(int * A, int n)
 6 {
 7     int nStart = A[0];
 8     int nAll = A[0];
 9     for(int i = 1;i < n;++ i)
10     {
11         nStart = max(A[i], nStart + A[i]);
12         nAll = max(nStart, nAll);
13     }
14     return nAll;
15 }
16 int main()
17 {
18     cout << "Hello world!" << endl;
19     int array[] = {10, -1, 3, -11, -20, 33, 1, -6, 13};
20     cout << MaxSubArray(array, sizeof(array)/sizeof(int)) << endl;
21     return 0;
22 }

 

posted @ 2013-09-13 13:59  Matrix_R  阅读(2355)  评论(1编辑  收藏  举报