题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
看见题目之后还是本能的想到用笨笨的方法去实现,即分别从n为奇数和偶数的角度去考虑,这样的思路比较清晰,记录一下(这里摘自Java版答案中的分析,我觉得语言组织得比我自己的好多了,故摘抄一下):
链接:https://www.nowcoder.com/questionTerminal/c451a3fd84b64cb19485dad758a55ebe
来源:牛客网
1)由于我们要找的是和为S的连续正数序列,因此这个序列是个公差为1的等差数列,而这个序列的中间值代表了平均值的大小。假设序列长度为n,那么这个序列的中间值可以通过(S / n)得到,知道序列的中间值和长度,也就不难求出这段序列了。
2)满足条件的n分两种情况:
n为奇数时,序列中间的数正好是序列的平均值,所以条件为:(n & 1) == 1 && sum % n == 0;
n为偶数时,序列中间两个数的平均值是序列的平均值,而这个平均值的小数部分为0.5,所以条件为:(sum % n) * 2 == n.
3)由题可知n >= 2,那么n的最大值是多少呢?我们完全可以将n从2到S全部遍历一次,但是大部分遍历是不必要的。为了让n尽可能大,我们让序列从1开始,
图中代码不够简洁,重复率高,只是为了展示清晰。上述代码在pycharm中自行调试时ok的,但是在牛客中提交结果是算法复杂度太大,或是超出内存限制,所以只能求助于答案中国中的神解答了(唉笨),以下记录一下:
设定两个指针,先分别指向数字1和数字2,并设这两个指针为small和big,对small和big求和,如果和大于目标值,则从当前和中删除small值,并把small值加一,如果和小于目标值,则把big值加一,再把新的big值加入和中。如果和等于目标值,就输出small到big的序列,同时把big加一并加入和中,继续之前的操作。(看答案都看半天才看懂,打死我也想不出这样的答案啊TT)
也就是通过两个指针遍历了半个数组的全部组合可能