題目:
輸入一個整型數組,數據元素有正數也有負數,求元素組合成連續子數組之和最大的子數組,要求時間複雜度爲O(n)。
例如:
輸入的數組爲1, -2, 3, 10, -4, 7, 2, -5,最大和的連續子數組爲3, 10, -4, 7, 2,其最大和爲18。
背景:
本題最初爲2005年浙江大學計算機系考研題的最後一道程序設計題,在2006年裏包括google在內的很多知名公司都把本題當作面試題。
由於本題在網絡中廣爲流傳,本題也順利成爲2006年程序員面試題中經典中的經典。
分析:
如果不考慮時間複雜度,我們可以枚舉出所有子數組並求出他們的和。不過非常遺憾的是,由於長度爲n的數組有O(n2)個子數組(即:n + n-1 + ... + 1=n(n+1)/2);而且求一個長度爲n的數組的和的時間複雜度爲O(n)。因此這種思路的時間是O(n3)。
很容易理解,當我們加上一個正數時,和會增加;當我們加上一個負數時,和會減少。如果當前得到的和是個負數,那麼這個和在接下來的累加中應該拋棄並重新清零,不然的話這個負數將會減少接下來的和。基於這樣的思路,我們可以寫出如下代碼。
- void MaxSum(int array[], unsigned int len)
- {
- if(NULL == array || len <=0){
- return;
- }
- int curSum = 0, maxSum = 0;
- int i = 0;
- for(i=0; i<len; i++){
- curSum += array[i]; // 累加
- if(curSum < 0){ // 當前和小於0,重置爲0
- curSum = 0;
- }
- if(curSum > maxSum){ // 當前和大於最大和,則重置最大和
- maxSum = curSum;
- }
- }
- if(maxSum == 0){ // 最大和依然爲0,說明數組中所有元素都爲負值
- maxSum = array[0];
- for(i=1; i<len; i++){
- if(array[i] > maxSum){
- maxSum = array[i];
- }
- }
- }
- printf("maxSum: %d", maxSum);
- }
測試數組:
- int array[] = {1, -2, 3, 10, -4, 7, 2, -5}; // 3, 10, -4, 7, 2 = 18
代碼改進:
有時,需要輸出最大和的子數組及其開始、結束下標,代碼如下:
- void MaxSum(int array[], unsigned int len)
- {
- if(NULL == array || len <=0){
- return;
- }
- int curSum = 0, maxSum = 0;
- int index_start = 0, index_end = 0; // 初始化子數組最大和下標
- int i = 0;
- for(i=0; i<len; i++){
- curSum += array[i]; // 累加
- if(curSum < 0){ // 當前和小於0,重置爲0
- curSum = 0;
- index_start = i+1; // 調整子數組最大和的開始下標
- }
- if(curSum > maxSum){ // 當前和大於最大和,則重置最大和
- maxSum = curSum;
- index_end = i; // 調整子數組最大和的結束下標
- }
- }
- if(maxSum == 0){ // 最大和依然爲0,說明數組中所有元素都爲負值
- maxSum = array[0];
- index_start = index_end = 0; // 初始化子數組最大和下標
- for(i=1; i<len; i++){
- if(array[i] > maxSum){
- maxSum = array[i];
- index_start = index_end = i; // 調整子數組最大和下標
- }
- }
- }
- // 輸出最大和的子數組及其開始、結束下標
- printf("index_start: %d\nindex_end: %d\n", index_start, index_end);
- for(i=index_start; i<=index_end; i++){
- printf("%d\t", array[i]);
- }
- printf("\n\nmaxSum: %d", maxSum);
- }
測試數組:
- int array[] = {1, -2, 3, 10, -4, 7, 2, -5}; // 3, 10, -4, 7, 2 = 18