• 和为S的连续正数序列


    知识点 穷举

    描述

            小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?

    数据范围:0 < n< 100
    进阶:时间复杂度 O(n)

    返回值描述

            输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序.

    解题思路

            求某个连续序列,很容易想到可以使用两个指针,一个指向序列头,一个指向序列尾。两个指针区间内的值的相加和语给定值比较。整个数组其实就是从1~n的正数组成所有数(想象有这么一个数组,不用真的去创建这么一个数组)。

    假设传入的值为sum, 使用ArrayList> list存放所有满足条件的序列:

            1、头、尾指针最开始都执行数组第一和第二个数据,即head=1, tail=2。用一个变量add来保存head~tail序列范围内数字相加和,所以初始add=head + tail = 3。还有为了保存所有满足条件的序列,使用一个列表ArrayList sublist变量来保存head~tail区间内的数字。

            2、开启循环,循环条件是head<=sum && tail < sum && head < tail,

            3、比较add和sum值,

                    如果add = sum,则当前head~tail区间的序列满足条件。创建一个新的ArrayList temp来存放这个序列区间的值,然后把list.add(temp)。然后让add变小,则把sublist中的head从列表中移除,然后add = add - head。再把head往后移动一步,即head++。进入下一次循环;

                    如果add < sum,需要让add变大,则往后移动tail一步,即add++,并且存入sublist中,再调整add = add + tail。进入下一次循环;

                    如果add > sum,需要让add变小,则把sublist中的head从列表中移除,然后add = add - head。再把head往后移动一步,即head++。进入下一次循环;

            4、循环结束后,list就是我们想要的结果啦。

            有几点需要注意下,当找到目标序列后,需要创建一个新的ArrayList 对象来保存序列内的值,而不能直接使用sublist,这是因为sublist在循环中是动态变化的。如果list.add(sublist)会导致list循环后只保存了最后一个满足条件的序列的数据,并且这个对象在循环中不断变化。

            算法中还使用了变量add动态地求出了head~tail区间内的数据和,这点还蛮好的。

    代码实现如下:

    1. import java.util.ArrayList;
    2. public class Solution {
    3. public ArrayList > FindContinuousSequence(int sum) {
    4. //用两个指针来遍历数组,两个指针区间的数字和等于目标值,则存入目标列表中
    5. ArrayList > list = new ArrayList >();
    6. int before = 1;
    7. int after =2;
    8. int add = 3;
    9. ArrayList subList = new ArrayList();
    10. subList.add(1);
    11. subList.add(2);
    12. while (before <= sum/2 && before < after && after < sum) {
    13. if (add == sum) {
    14. ArrayList tempList = new ArrayList(); //创建一个为空临时列表来存储符合条件的数据集合
    15. tempList.addAll(subList);
    16. list.add(tempList);
    17. if (subList.size() >=1) {
    18. subList.remove(0);
    19. }
    20. add = add - before;
    21. //搞了半天一直调试不通过是因为这里写错了,这种写法会导致before变量在循环过程中保持不变
    22. //before = before++;
    23. before++;
    24. } else if (add > sum) {
    25. if (subList.size() >=1) {
    26. subList.remove(0);
    27. }
    28. add = add - before;
    29. //搞了半天一直调试不通过是因为这里写错了,这种写法会导致before变量在循环过程中保持不变
    30. //before = before++;
    31. before++;
    32. } else {
    33. after++;
    34. subList.add(after);
    35. add = add + after;
    36. }
    37. }
    38. return list;
    39. }
    40. }

            还有一点特别强调下:在调试的时候一直报错,但是检查逻辑没发现什么问题。后来通过打断点调试,发现代码中的before变量在循环过程中一直保持为1,没有变化。这个很奇怪。

            刚开始使用的是before = before++; 罪魁祸首就是这里了,这种写法会导致before永远不变(具体原因参考文章:"Java中关于a=a++结果的解释"和“a=a++理解​​​​​​​”)。把before = before++;替换成before++;,运行后正常了!!

            最后,关于这道算法题,网上给出了好几种解法,可以参考和为S的连续正数序列_楚楚可薇的博客-CSDN博客_和为s的连续正数序列

  • 相关阅读:
    可验证的idea才是真的
    2020年全国职业院校技能大赛改革试点赛样卷二
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    MyBatis中如何实现一个分页功能呢?
    不用addEventListener(‘resize‘, this.resize),用新的Web API ResizeObserver监听DIV元素尺寸的变化
    手撕Vue-实现事件相关指令
    Redis分布式缓存(二)| 主从架构搭建、全量/增量同步原理、主从同步优化
    return_punctuation
    简单聊聊羊了个羊
    Fragment切换的方式介绍和一些问题的解决
  • 原文地址:https://blog.csdn.net/liuqinhou/article/details/126187000