PAT 甲级刷题实录——1007

本贴最后更新于 1803 天前,其中的信息可能已经渤澥桑田

原题链接

寻找解法

这题一开始有点懵,一开始以为是选个固定长度的最大子串,那样会简单很多。但并不是,子串的长度是没有限制的,于是复杂度一下子上去了。自己之前没有遇到过这样的问题,于是上网搜索了别人的做法。说实话,有一些解法我是想都不敢去想的,也佩服有些人还真敢用,比如这篇文章的:https://blog.csdn.net/weixin_42267752/article/details/82414578
这个算法完全就是硬算,时间复杂度高到爆炸,亏他还好意思说是大神

之后又参考了这篇文章的:https://www.cnblogs.com/Breathmint/p/10275935.html
这篇文章的水准明显就高了,首先他没有用数组,而是在输入数据的同时就进行计算,一下子就把空间复杂度降到了 O(1)。另外他的算法也非常精妙,当数据输入完毕时结果也已经计算出来。大家可以看这篇文章里的思路,我的算法对这篇文章的算法做了一点小小的改进,代码如下,大家可以同时参考一下。

代码

#include <iostream>
using namespace std;
int main()
{
	int num;	//数字个数
	int currentSum=0;	//记录子串之和
	int maxSum = -1;	//最大子串之和
	int subFirst, subLast;	//记录最大子串的第一个和最后一个数字
	int startFlag;	//目前计算的子串的首元素
	bool updateFlag = false;	//用来记录是否在下一次循环中更新startFlag
	int first, last;	//记录整个数字串的第一个和最后一个数字
	int currentNum;	//记录当前读取的数字
	cin >> num;
	for (int i = 0; i < num; i++)
	{
		cin >> currentNum;
		if (i == 0)
			subFirst = subLast = startFlag = first = currentNum;	//初始化并确定first
		if (i == num-1)
			last = currentNum;
		currentSum += currentNum;	//计算目前计算的子串之和
		if (updateFlag == true)	//根据上一次循环的标记更新startFlag
		{
			startFlag = currentNum;
			updateFlag = false;
		}
		if (currentSum > maxSum)	//目前计算的子串之和大于已知的最大子串和,则更新最大子串和,同时更新最大子串的首元素和尾元素
		{
			subFirst = startFlag;	//更新最大子串的首元素
			subLast = currentNum;	//更新最大子串的尾元素
			maxSum = currentSum;	//更新最大子串和
		}
		if (currentSum < 0)	//当前计算的子串之和小于0,则重新从零开始计算子串之和,同时标记下一次循环中更新startFlag
		{
			currentSum = 0;		//重新从零开始计算currentSum
			updateFlag = true;		//记录下一次循环中更新startFlag
		}
	}
	if (maxSum == -1)	//全是负数
	{
		cout << 0 << ' ' << first << ' ' << last;
	}
	else
	{
		cout << maxSum << ' ' << subFirst << ' ' << subLast;
	}
	return 0;
}

思路以及改进

在运算过程中,子串分为最大子串和目前计算的子串。算法的基本思路为:每次都将本轮循环读取到的元素加到目前计算的子串之和中。当目前计算的子串之和大于已知的最大子串之和时,就要更新最大子串之和以及最大子串的首元素和尾元素,其中首元素更新为之前已经记录的目前计算的子串的首元素(下文会说何时记录),尾元素为当前读取的元素。因为最大子串之和不能为负数,所以每次当目前计算的子串之和 <0 时,就要重新将目前计算的子串之和从 0 开始计算,另外将目前计算的子串的首元素设置为下一轮循环读到的元素(这里需要读者细细地理解一下)。

原文章的代码中设置了一个标记为 leftFlag,并将它设为 0 代表下一轮循环更新目前计算的子串的首元素。但我认为这样不妥,因为在原文章的代码中 leftFlag 既承担了判断是否更新目前计算的子串的首元素的作用,也承担了存储目前计算的子串的首元素的作用,而如果数字串中读取到 0 元素赋给 leftFlag,就会干扰到目前计算的子串的首元素的更新。我的改进是另外设一个 bool 变量,用 true 代表更新 leftFlag。同时我发现原文章的代码中 rightFlag 并没有起到作用,因此我就删减了这个变量,并把 leftFlag 重新命名为 startFlag。

  • PAT
    25 引用 • 1 回帖 • 1 关注
  • C++

    C++ 是在 C 语言的基础上开发的一种通用编程语言,应用广泛。C++ 支持多种编程范式,面向对象编程、泛型编程和过程化编程。

    107 引用 • 153 回帖

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...