问题描述
输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:
序列:-2 11 -4 13 -5 -2,则最大子序列和为20。
复杂度为O(N^2)的算法
#include <stdio.h>
#include <stdlib.h>
int MaxSubSeqSum(const int *A, int N, int *start, int *end)
{
int i = 0;
int j = 0;
int cur_sum = 0;
int Max_sum = 0;
for(i = 0; i < N; i ++)
{
cur_sum = 0;
for(j = i; j < N; j ++)
{
cur_sum += A[j];
if(cur_sum > Max_sum)
{
Max_sum = cur_sum;
*start = i;
*end = j;
}
}
}
return Max_sum;
}
int main()
{
int A[] = {-2,11,-4,13,-5,-2};
int start_index, end_index;
int max = MaxSubSeqSum(A,sizeof(A)/sizeof(A[0]),&start_index,&end_index);
printf("MaxSubSeqSum is %d -- %d \n",A[start_index],A[end_index]);
printf("max:%d \n",max);
}
算法度为O(NlogN)的算法
采用的是“分治“(divide-and-conquer)策略。思想是把问题分成两个大致相当的子问题,然后递归地对他们求解,这是”分“。”治“阶段将两个子问题的解合并到一起,可能再做一些附加的工作,最终得到整个问题的解。
上述问题,把序列分为两部分,最大子序列可能出现在左半部分,或者右半部分,或者是两者之间。两者之间的情况下,先对左半部分求以最后一个数字为结尾的最大序列和。然后对右半部分以第一个数字开始算最大序列和,将两者加起来即是。
int Max_3(int a, int b, int c)
{
if(a < b)
a = b;
if(a < c)
return c;
else
return a;
}
int MaxSubSeqSum2(const int *A, int left, int right)
{
int MaxLeftSum, MaxRightSum, MaxSum;
int MaxLeftBorderSum, MaxRightBorderSum;
int LeftBorderSum, RightBorderSum;
int center;
int i;
if( left == right)
{
if(A[left] > 0)
return A[left];
else
return 0;
}
center = (left + right) / 2;
MaxLeftSum = MaxSubSeqSum2(A,left,center);
MaxRightSum = MaxSubSeqSum2(A,center + 1,right);
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;
}
MaxSum = Max_3(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
return MaxSum;
}
算法复杂度为O(N)的算法
/* 如果a[i]为负数,那么它不可能代表最优序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过
用a[i+1]作为起点而得到改进。同理,任何小于零的子序列不可能是最优子序列的前缀。*/
int MaxSubSeqSum3(const int *A, int N, int *start, int *end)
{
int i = 0;
int j = 0;
int cur_sum = 0;
int Max_sum = 0;
for(i = 0; i < N; i ++)
{
cur_sum += A[i];
if(cur_sum > Max_sum)
{
Max_sum = cur_sum;
*end = i;
}
else if(cur_sum < 0)
{
cur_sum = 0;
j = i + 1;
}
if(j <= *end)
*start = j;
}
return Max_sum;
}
int main()
{
int A[] = {-2,11,-4,13,-5,-2};
int start_index, end_index;
int max = MaxSubSeqSum3(A,sizeof(A)/sizeof(A[0]),&start_index,&end_index);
printf("MaxSubSeqSum is %d -- %d \n",A[start_index],A[end_index]);
printf("max:%d \n",max);
}
参考: http://www.cnblogs.com/CCBB/archive/2009/04/25/1443455.html