最大子序列和问题 分治算法

来源:互联网 发布:mac 卸载java jdk 编辑:程序博客网 时间:2024/05/15 04:37

问题:给定整数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;elsereturn Center;}elseif(Right > Center)return Right;elsereturn 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];elsereturn 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;elseif(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;}