最大子序列
最大子序列问题
给定整数 A1,A2......,Ak (可能为负数), 求∑jk=iAk 的最大值
第一种算法是最通俗易懂的算法,穷举法,算法复杂度O(N3)
1 int MaxSubsequenceSum( const int A[], int N ) 2 { 3 int ThisSum, MaxSum, i, j, k; 4 MaxSum = 0; 5 for( i = 0; i < N ; i++ ) 6 { 7 for( j = 0; j<N;j++ ) 8 { 9 ThisSum = 0; 10 for( k=i;k<=j;k++) ThisSum += A[k]; 11 if( MaxSum < ThisSum ) MaxSum = ThisSum; 12 } 13 } 14 }
分析第一种算法发现, 第五步跟第七步的效率比较低, 每次都重新计算总和, 因为∑jk=iAk = Aj + ∑j-1k=i Ak, 所以没有必要每次重复计算,复杂度O(N2)。
第二种解法:
int MaxSubsequenceSum( const int A[], int N ) { int ThisSum, MaxSum, i, j, k; MaxSum = 0; for( i = 0; i < N ; i++ ) { ThisSum = 0; for( j = 0; j<N;j++ ) { ThisSum += A[k]; if( MaxSum < ThisSum ) MaxSum = ThisSum; } } return MaxSum; }
第三种算法是递归思想,算法复杂度是O(NlogN)。
递归思想是把队列分成两半, 分别求两半各自的最大值跟两者合起来后包含左半部分最后一个右半部分第一个连续串的最大值。
通过分治思想,把问题递归处理。
static int MaxSubSum( const int A[], int Left, int Right ) { int MaxLeftSum, MaxRightSum; int MaxLeftBorderSum, MaxRightBorderSum; int LeftBorderSum, RightBorderSum; int Center, i; if( Left == Right ) { if( A[Left] > 0 ) return A[Left]; else return 0; } Center = (Left + Right ) / 2 ; MaxLeftSum = MaxSubSum( A, Left, Center ); MaxRightSum = MaxSubSum( A, Center, Right ); LeftBorderSum = 0; RightBorderSum = 0; MaxLeftBorderSum = 0; MaxRightBorderSum = 0; for( i = center; i >= Left; i--) { LeftBorderSum += A[i]; if( LeftBorderSum > MaxLeftBorderSum ) MaxLeftBorderSum = LeftBorderSum; } for( i = center; i <= Right; i++) { RightBorderSum += A[i]; if( RightBorderSum > MaxRightBorderSum ) MaxRightBorderSum = RightBorderSum; } return Max3( MaxLeftSum,MaxRightSum, MaxLeftBorderSum+MaxRightBorderSum ); } int MaxSubquenceSum( const int A[], int N ) { return MaxSubSum( A, 0, N ); }
第四种算法,简单更为有效
int MaxSubquenceSum( const int A[], const int N ) { int ThisSum, MaxSum, J; ThisSum = MaxSum = 0; for( j = 0; j < N; j++ ) { ThisSum += A[j]; if( ThisSum > MaxSum ) MaxSum = ThisSum; else if( ThisSum < 0 ) ThisSum = 0; } return MaxSum; }

浙公网安备 33010602011771号