问题
给定一个数列,其中可能有正数也可能有负数,我们的任务是找出其中连续的一个子数列(不允许空序列),使它们的和尽可能大。
算法一:时间复杂度O(N^3)
/*算法一*/
int MaxSubseqSum1(int A[], int N) {
int ThisSum, MaxSum = 0;
int i, j, k;
for(i = 0; i < N; i++) { //i是子列左端位置
for(j = i; j < N; j++) { //j是子列右端位置
ThisSum = 0; //ThisSum是从A[i]到A[j]的子列和
for(k = i; k <= j; k++) {
ThisSum += A[k];
}
if(ThisSum > MaxSum) { //如果刚得到的子列和比MaxSum更大
MaxSum = ThisSum; //则更新结果
}
} //j循环结束
} //i循环结束
return MaxSum;
}
算法二:时间复杂度O(N^2)
/*算法二*/
int MaxSubseqSum2(int A[], int N) {
int ThisSum, MaxSum = 0;
int i, j;
for(i = 0; i < N; i++) { //i是子列左端位置
ThisSum = 0; //ThisSum是从A[i]到A[j]的子列和
for(j = i; j < N; j++) { //j是子列右端位置
ThisSum += A[j]; //对于相同的i,不同的就,只要在j-1次循环的基础上累加一项即可
if(ThisSum > MaxSum) { //如果刚得到的子列和比MaxSum更大
MaxSum = ThisSum; //则更新结果
}
} //j循环结束
} //i循环结束
return MaxSum;
}
算法三:分治法,时间复杂度O(NlogN)
/*算法三:分治法*/
/*返回三个整数的最大值*/
int Max3(int A, int B, int C) {
return (A > B) ? (A > C ? A : C) : (B > C ? B : C);
}
/*分治法求List[left]到List[right]的最大子列和*/
int DivideAndConquer(int List[], int left, int right) {
int MaxLeftSum, MaxRightSum; //存放左右子问题的解
int MaxLeftBorderSum, MaxRightBorderSum; //存放跨分界线的结果
int LeftBorderSum, RightBorderSum;
int center, i;
/*递归的终止条件,子列只有1个数字*/
if(left == right) {
if(List[left] > 0)
return List[left];
else
return 0;
}
/*“分”的过程 */
center = (left + right) / 2; //找到中分点
MaxLeftSum = DivideAndConquer(List, left, center); //递归求左子列和
MaxRightSum = DivideAndConquer(List, center + 1, right); //递归求右子列和
/*求跨分界线的最大子列和*/
MaxLeftBorderSum = 0;
LeftBorderSum = 0;
for(i = center; i >= left; i--) {
LeftBorderSum += List[i];
if(LeftBorderSum > MaxLeftBorderSum)
MaxLeftBorderSum = LeftBorderSum;
}//左边扫描结束。
MaxRightBorderSum = 0;
RightBorderSum = 0;
for(i = center + 1; i <= right; i++) {
RightBorderSum += List[i];
if(RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}//右边扫描结束。
/*返回“治”的结果*/
return Max3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
/*此函数用于保持接口相同*/
int MaxSubseqSum3(int List[], int N) {
return DivideAndConquer(List, 0, N-1);
}
算法四:在线处理,时间复杂度O(N)
/*算法四:在线处理*/
int MaxSubseqSum4(int A[], int N) {
int ThisSum, MaxSum;
int 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;
}
最后,写一个主函数进行测试,第1行输入正整数n;第2行给出n个整数,其间以空格分隔。
#include <stdio.h>
#define MAX 100000
int main() {
int n, i;
int a[MAX] = {0};
scanf("%d", &n);
for ( i = 0; i < n; i++ )
scanf("%d", &a[i]);
printf("%d", MaxSubseqSum1( a, n ));
return 0;
}