问题:给定整数A1,A2,·······,An,求该序列中所有子序列(包括本序列)中的元素和最大值,如果所有整数均为负数,则最大子序列和为0
算法一:穷举法。运行时间为O(N3)
代码:
int MaxSubsequenceSum(const int A[], int N) { int ThisSum, MaxSum, i,j,k; MaxSum = 0; for(i = 0; i< N; i++) { for(j = i; j < N; j++) { ThisSum = 0; for(k = i; k <= j; k++) ThisSum += A[k]; if(ThisSum > MaxSum) MaxSum = ThisSum; } } return MaxSum; }
算法二:撤销算法一的一个for循环,运行时间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 = i; j < N; j++) { ThisSum += A[j]; if(ThisSum > MaxSum) MaxSum = ThisSum; } } return MaxSum; }
算法三:分治算法,相对复杂度的O(NlogN)解法
把问题分成两个大致相等的子问题,然后递归的对它们求解,这是“分”部分。“治”阶段将两个子问题的解合并到一起并可能再做一些少量的附加工作,最后得到整个问题的解。
在本题中,最大子序列和可能在三处出现。或者整个出现在输入数据的左半部分,或者整个出现在右半部分,或者跨越输入数据的中部从而占据左右两半部分。前两种情况可以递归求解, 第三种情况的最大和可以通过求出前半部分的最大和(从前半部分的最后一个元素开始查找,必须包含最后一个元素的序列)以及后半部分的最大和(包含后半部分的第一个元素)而得到。然后这两个和加在一起。
代码:
int Max3(int Left, int Right, int Center) { cout<<"Left = "<<Left<<'\t' <<"Right = "<<Right<<'\t' <<"Center = "<<Center<<endl; if(Left > Right) { if(Left > Center) return Left; else return Center; } else if(Right > Center) return Right; else return Center; } 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+1, Right); /* * 处理在Center两边交叉的元素可能构成的最大子序列和的可能 * 求出左半部分从Center元素开始,向左寻找子序列的最大和 MaxLeftBorderSum * 求出有半部分从Center + 1开始的,向右寻找子序列的最大和 MaxRightBorderSum * 然后将 MaxLeftBorderSum + MaxRightBorderSum 就是在Center两边交叉元素可能构成的最大子序列的和 */ MaxLeftBorderSum = 0; LeftBorderSum = 0; for(i = Center; i >= Left; i--) { LeftBorderSum += A[i]; if(LeftBorderSum > MaxLeftBorderSum) MaxLeftBorderSum = LeftBorderSum; } MaxRightBorderSum = 0; RightBorderSum = 0; for(i = Center + 1; i <= Right; i++) { RightBorderSum += A[i]; if(RightBorderSum > MaxRightBorderSum) MaxRightBorderSum = RightBorderSum; } return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum); } int MaxSubsequenceSum(const int A[], int N) { return MaxSubSum(A, 0, N - 1); }
算法四:直接判断,若前一个子序列的和小于 0, 则按和为0计算
代码:
int MaxSubsequenceSum(const int A[], int N) { int ThisSum, MaxSum, i; ThisSum = MaxSum = 0; for(i = 0; i < N; i++) { ThisSum += A[i]; if(ThisSum > MaxSum) MaxSum = ThisSum; else if(ThisSum < 0) ThisSum = 0; } return MaxSum; }
补充:当所有元素全是负数时要求也是求出最大的和,应该改成这样:
int max_sub_array_sum2(int* array, int len) { if(array == NULL || len < 0) exit(1); int max_sum = array[0]; int cur_sum = array[0]; for(int i=1; i < len; i++) { cur_sum += array[i]; if(cur_sum < array[i]) { cur_sum = array[i]; } if(cur_sum > max_sum) { max_sum = cur_sum; } } return max_sum; }