题目详情
题目分析:
- 这是7-1 最大子列和问题的升级版,可以看我这篇题解,方法差不多,唯一的区别就是记录最大子列和的首数字和尾数字
- 我想到了差分数组,先一边输入一边一个个累加,连续的序列和等于差分数组两个数的差,只要遍历差分数组,用在差分数组中遍历到的数字减差分数组中这个数之前的最小的数,等于当前遍历到的数为序列尾的最大连续序列和。遍历所有差分数组里的数,找到最大值。
- 一共num个数
- tem当前输入的数字
- minn表示在差分数组中当前遍历到的数字之前的最小的序列和(也就是在差分数组中当前遍历到的数字之前最小的数字)
- maxsum表示当前找到的最大连续序列和
- 下面程序一边输入一边计算最大值,降低时间复杂度
- maxsum要设置为最小值,因为序列里有负数
- firstNum用来记录整个第一个数,之所以用maxsum == -0x3f3f3f这个条件判断,是因为maxsum只有一开始才等于-0x3f3f3f,所以此时输入的数据就是整个序列第一个数据
- lastNum当num变成0的时候,此时输入的数据就是整个序列最后一个数字
- minn之所以不设为无穷大的值,是因为整个序列有可能只有一个数字,这样minn还没来得及更新就已经用了这样sum - minn将是一个很离谱的值
#include <cstdio>
int num, tem, minn, maxsum = -0x3f3f3f, sum, first, end, ss, firstNum, lastNum;
int main()
{
int firstFlag = 0, endFlag = 0;
scanf("%d", &num);
while (num--)
{
scanf("%d", &tem);
sum += tem;
if (maxsum == -0x3f3f3f)
firstNum = first = tem;//第一次初始化序列首元素为第一个数字,因为可能这个序列只有一个数字,此时首位元素相同,故需要此步骤
if (firstFlag == 1)
first = tem, firstFlag = 0;
if (num == 0)
lastNum = tem;
maxsum = (sum - minn) > maxsum ? (ss = first, end = tem, sum - minn) : maxsum; //(ss = first, end = tem, sum - minn) 逗号表达式,这个表达式先按顺序执行,最后返回最后一个表达式的值作为整个表达式的值,一旦maxsum被更新,那么说明我们找到了一个更优的解,这个时候我们就需要把最近更新的序列开头数字作为目前这个更优序列的开头(用ss记录),而结尾就是当前循环输入的数字
minn = sum < minn ? (firstFlag = 1, sum) : minn;//一旦minn被更新了,那么说明下一个输入的数字有可能作为最大序列和的开头,所以设置一个flag让程序将下一个数字记录下来
}
if (maxsum >= 0)
printf("%d %d %d", maxsum, ss, end);
else
printf("0 %d %d", firstNum, lastNum);//题目要求不能忘了
}