给定a个整数组成的序列{},将序列中连续排列的整数构成的新序列定义为连续子列,最大子列和被定义为序列{
}中最大的连续子列。编写一个程序,要求输入一个整数序列,返回它的最大子列和。
算法1:暴力解法
算法1的思想是引入两个变量ThisSum和MaxSum,前者用来控制连续子列的当前值,后者用来存放连续子列的最大值,对数组内的值从前往后进行依次求和,并且每次求和之后都要对比ThisSum和MaxSum的值,若ThisSum更大,则更新MaxSum的值,每遍历一次数组的各个元素,就扔掉第一个元素(没错,下标为 i 的元素,你已经没有利用价值了),最后返回MaxSum。
代码如下
//算法1
int MaxSubseqSum1(int A[], int N)
{
int ThisSum, MaxSum = 0;
int i, j;
for (i = 0; i < N; i++)
{
ThisSum = 0;
{
for (j = i; j < N; j++)
{
ThisSum += A[j];
if (ThisSum > MaxSum)
MaxSum = ThisSum;
}
}
}
return MaxSum;
}
//算法1时间复杂度为O(N^2)
算法2:采用递归分而治之
太复杂了而且有急事,下次写doge,大家可以按照自己的理解将就看看,或者直接快进到算法3,反正算法2的时间复杂度也不是很好。
//算法2,分开用递归求解
int Max(int A, int B, int C)//返回三个整数中的最大值
{
return A > B ? A > C ? A : C : B > C ? B : C;
}
int DivideAndConquer(int List[], int left, int right)
{
int MaxLeftSum, MaxRightSum;//存放左右子问题的解
int MaxLeftBorderSum, MaxRightBorderSum;//存放跨分界线的结果
int LeftBorderSum, RightBorderSum; //存放跨分界线当前值
int center, i;
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;
}//左边扫描结束
MaxLeftBorderSum = 0; LeftBorderSum = 0;
for (i = center + 1; i <= right; i++)
{
RightBorderSum += List[i];
if (RightBorderSum > MaxRightBorderSum)
MaxRightBorderSum = RightBorderSum;
}//右边扫描结束
return Max(MaxLeftSum, MaxRightSum, MaxLeftBorderSum + MaxRightBorderSum);
}
int MaxSubseqSum2(int List[], int N)
{
return DivideAndConquer(List, 0, N - 1);
}
//算法2时间复杂度为O(NlogN)
算法3:动态求解
与算法1相比,ThisMax用来存放正值,若为负值则直接舍去,随着 i 的增长,会不断更新ThisMax的值(初始化为0或加上下一个值),所以是动态的。以下图为例,第一个值为-5,直接舍去,后面的连续子列的判断也不带上第一个值,第二个值到第四个值的和为-1,也是舍去,在更新ThisMax的过程中与MaxSum进行对比,并保留最大值。
代码如下
//算法3
int MaxSubseqSum3(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;
}
//算法3的时间复杂度为O(N)