摘要:给出一个序列,求出其中连续的子序列中和最大的一个。(如 1 3 -5 2 -1 4 5)最大子序列之和是2 -1 4 5
基本思路:
【1】最简单的办法就是遍历一边序列,用变量Thissum记录遍历过的元素之和,当Thisum>0时,继续相加.若Thisum < 0,令Thisum = 0,吧下一个元素作为新的子序列的开头.同时检测所有Thissum的最大值.这个算法很容易理解:因为如果Thissum>0,那么加上后面的元素有可能产生最大值,但如果Thissum<0,那么包括它一定不会产生最大值.
【2】尽管方法【1】的效率是O(N),而且编程简单,但是适用范围只限于加法或者减法.这里还有一种更通用的方法,分治算法。
基本思路:将该序列分为2部分,求出左边与右边最大和,然后从中间开始向两边遍历找出经过中间的最大子序列,将三个值进行比较。对于两部分的也是递归的计算,时间界是O(NlogN);
推算时间界
T(N) = 2T(2/N) + O(N);不妨令N = 2^k,T(1) = 1;
T(2^k) = 2T(2^(k-1)) + 2^k,
->T(2^k)/2^k = T(2^(k-1))/(2^(k-1)) + 1;
所以T(2^k)/2^k = K;T(N) = NlogN;
#include "stdafx.h"
#include "stdlib.h"
#define Positive 0
#define Negative 1
int Max3(int a, int b, int c)
{
a = (a>b?a:b);
return (a>c?a:c);
}
//求最大子序列之和
static int Maxsub(const int A[],int Left, int Right)
{
int Max_Left,Max_Right;
int center;;
int LeftBodersum,RightBodersum;
int Max_LeftBodersum, Max_RightBodersum;
if (Left == Right)//处理基准情况
{
if (A[Left]>0)
return A[Left];
else
return 0;
}
center = (Left + Right)/2;
Max_Left = Maxsub(A,Left,center);
Max_Right = Maxsub(A,center+1,Right);
LeftBodersum = 0;
RightBodersum = 0;
Max_LeftBodersum = 0;
Max_RightBodersum = 0;
for (int i = center;i>=Left;i--)
{
LeftBodersum +=A[i];
if (LeftBodersum >= Max_LeftBodersum)
Max_LeftBodersum = LeftBodersum;
}
for (int i = center+1;i<=Right;i++)
{
RightBodersum +=A[i];
if (RightBodersum >= Max_RightBodersum)
Max_RightBodersum = RightBodersum;
}
return Max3(Max_Left,Max_Right,Max_LeftBodersum+Max_RightBodersum);
}