输入一组整数,求出这组数字子序列和中最大值。也就是只要求出最大子序列的和,不必求出最大的那个序列。例如:{4,-3,5,-2,6,-7,1}的最大子序列和是10。
算法1,
//穷举法,时间复杂度O(N^3)
int MaxSub(int Data[])
{
int len = sizeof(Data)/sizeof(int);
int MaxSum = 0;
for (int i = 0;i <len;i++)
{
for (int j = i;j<len;j++)
{
int sum = 0;
for (int k = i;k<j;k++)
{
sum += Data[k];
}
if (MaxSum < sum)
{
MaxSum = sum;
}
}
}
return MaxSum;
}
算法2
//穷举法,时间复杂度O(N^2)
int MaxSub(int Data[])
{
int len = sizeof(Data)/sizeof(int)
int MaxSum = 0;
for (int i = 0;i<len;i++)
{
int sum = 0;
for (int j = i;j<len;j++)
{
sum += Data[j];
}
if (sum > MaxSum)
{
MaxSum = sum;
}
}
return MaxSum;
}
算法3
采用分治算法思想,时间复杂度O(NlogN);
最大序列只可能出现在序列的左边,右边或者跨越左右两边,用递归的方法可以解决问题。
int Max(int a,int b,int c)
{
int max = a;
if (max < b){
max = b;
}
if (max <c){
max = c;
}
return max;
}
int MaxSub(int first,int last,int Data[])
{
int lSum = 0;
int rSum = 0;
int lMaxSum = 0;
int rMaxSum = 0;
int middle = (first + last)/2;
if (last < first )
return 0;
if (last == first)
return Data[first];
int lData = MaxSub(first,middle,Data);
int rData = MaxSub(middle+1,last,Data);
lMaxSum = Data[middle];
for (int i = middle;i>=first;i--)
{
lSum += Data[i];
if (lSum > lMaxSum){
lMaxSum = lSum;
}
}
rMaxSum = Data[middle+1];
for (int j = middle+1;j<=last;j++)
{
rSum += Data[j];
if (rSum >rMaxSum)
{
rMaxSum = rSum;
}
}
int num = Max(rData,lData,rMaxSum + lMaxSum);
return num;
}
算法4
下面介绍一个线性的算法,这个算法是许多聪明算法的典型,时间复杂度为O(N)。
主要思想:如果a[i]是负数那么它不可能代表最大序列的起点,因为任何包含a[i]的作为起点的子序列都可以通过用a[i+1]作为起点来改进。类似的有,任何的负的子序列不可能是最优子序列的前缀。
long maxSubSum4(int a[],int len)
{
int maxsum, maxhere;
maxsum = maxhere = a[0]; //初始化最大和为a【0】
for (int i=1; i<len; i++)
{
if (maxhere <= 0)
maxhere = a[i]; //如果前面位置最大连续子序列和小于等于0,则以当前位置i结尾的最大连续子序列和为a[i]
else
maxhere += a[i]; //如果前面位置最大连续子序列和大于0,则以当前位置i结尾的最大连续子序列和为它们两者之和
if (maxhere > maxsum) {
maxsum = maxhere; //更新最大连续子序列和
}
}
return maxsum;
}
遍历到a[i]时,如果a[i]前面的子序列和小于零,则将maxhere置为a[i],因为负的子序列和不会优化得到最大子序列。