1.問題描述
一個有N個整數元素的一維數組( A[0], A[1], ... , A[n-2], A[n-1]),子數組之和的最大值是什么?(要求子數組的元素是連續的)
例子:有數組( -2, 5, 3, -6, 4, -8, 6),則其子數組之和的最大值為8,其對應的數組為(5,3)
2.分析與解法
解法一:采用直接法,記Sum[i...j],為數組A中從第i到第j之間所有數之和,算出所有Sum,取其最大,代碼如下,時間復雜度O(N2):
int maxSum1(int *A, int n) { int max = -1; int i, j, sum; for(i = 0; i < n; i++) { sum = 0; for(j = i; j < n; j++) { sum += A[j]; if(sum > max ) max = sum; } } return max; }
解法二:使用分治法,數組(A[0],A[1],...A(n-1)分為長度相等的兩段數組(A[0],...,A[n/2-1])以及(A[n/2],...,A[n-1]),分別求出這兩段數組各自的最大子段和,則原數組(A[0],A[1],...A(n-1)的最大子段和分為3種情況
1).(A[0],A[1],...A(n-1)的最大子段和與(A[0],...,A[n/2-1])的相同
2).(A[0],A[1],...A(n-1)的最大子段和與(A[n/2],...,A[n-1])的相同
3).(A[0],A[1],...A(n-1)的最大子段和跨過(A[0],...,A[n/2-1])與(A[n/2],...,A[n-1])-
1)和2)可以根據遞歸可得,3)只要計算出以A[n/2-1]為結尾的一段數組最大和s1=Sum1[i...n/2-1]和A[n/2]為開頭一段數組最大和s2=Sum2[n/2...j],最后s=s1+s2.
這個算法滿足分值算法遞歸,總的時間復雜度O(N*log2N)
解法三:假設我們已經知道(A[k].....A[n-1])最大的一段數組和為All[k],並且已經計算出在(A[k].....A[n-1])中包含A[k]的最大的一段數組和為Start[k],那么可以推斷出All[k-1]=max{A[k-1],A[k-1]+Start[k],All[k]},利用動態規划思想以及這樣的遞推公式,從后往前計算,代碼如下,時間復雜度O(N):
int max(int x, int y) { return (x > y) ? x : y; } int maxSum2(int *A, int n) { int i; int All[n], Start[n]; All[n-1] = A[n-1]; Start[n-1] = A[n-1]; for(i = n-2; i >= 0; i--) { Start[i] = max(A[i], A[i]+Start[i+1]); All[i] = max(All[i+1], Start[i]); } return All[0]; }
對以上代碼進行簡化,因為最后所求到的變量只有Start[0]和All[0],這樣可以反復用nStart和nAll,省略掉其他的變量,代碼如下:
int max(int x, int y) { return (x > y) ? x : y; } int maxSum2_v(int *A, int n) { int i; int nAll, nStart; nAll = A[n-1]; nStart = A[n-1]; for(i = n-2; i >= 0; i--) { nStart = max(A[i], A[i]+nStart); nAll = max(nAll, nStart); } return nAll; }
注:以上的計算順序也可以從前往后,即:All[k+1]=max{A[k+1],A[k+1]+Start[k],All[k]}.