題目:
輸入一個整型數組,資料元素有正數也有負數,求元素組合成 連續子數組之和最大的子數組,要求時間複雜度為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
運行結果: