PAT 甲级刷题实录——1007

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

原题链接

寻找解法

这题一开始有点懵,一开始以为是选个固定长度的最大子串,那样会简单很多。但并不是,子串的长度是没有限制的,于是复杂度一下子上去了。自己之前没有遇到过这样的问题,于是上网搜索了别人的做法。说实话,有一些解法我是想都不敢去想的,也佩服有些人还真敢用,比如这篇文章的: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 回帖 • 1 关注

相关帖子

欢迎来到这里!

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

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