经典面试题 之 子数组之和最大值
因为最近要开始笔试和面试了,我觉得,很有必要做好准备~
这个问题是我在网上看到的,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 }