和为S的连续正数序列

本文详细介绍了如何使用双指针法解决寻找所有和为S的连续正数序列的问题,强调了在循环中处理变量更新的细节,特别是避免使用`before=before++;`这种可能导致错误的写法。同时,提供了代码实现和调试过程中的注意事项,帮助读者理解算法思路和常见陷阱。
摘要由CSDN通过智能技术生成

知识点 穷举

描述

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

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

返回值描述

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

解题思路

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

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

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

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

        3、比较add和sum值,

                如果add = sum,则当前head~tail区间的序列满足条件。创建一个新的ArrayList<Integer> 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<Integer> 对象来保存序列内的值,而不能直接使用sublist,这是因为sublist在循环中是动态变化的。如果list.add(sublist)会导致list循环后只保存了最后一个满足条件的序列的数据,并且这个对象在循环中不断变化。

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

代码实现如下:

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       //用两个指针来遍历数组,两个指针区间的数字和等于目标值,则存入目标列表中
        ArrayList<ArrayList<Integer> > list = new ArrayList<ArrayList<Integer> >();
        int before = 1;
        int after =2;
        int add = 3;
        ArrayList<Integer> subList = new ArrayList<Integer>();
        subList.add(1);
        subList.add(2);
        while (before <= sum/2  && before < after && after < sum) {
            if (add == sum) {
                ArrayList<Integer> tempList = new ArrayList<Integer>(); //创建一个为空临时列表来存储符合条件的数据集合
                tempList.addAll(subList);
                list.add(tempList);
                if (subList.size() >=1) {
                    subList.remove(0);
                }
                add = add - before;
                //搞了半天一直调试不通过是因为这里写错了,这种写法会导致before变量在循环过程中保持不变
                //before = before++; 
                before++;
            } else if (add > sum) {
                if (subList.size() >=1) {
                    subList.remove(0);
                }
                add = add - before;
                //搞了半天一直调试不通过是因为这里写错了,这种写法会导致before变量在循环过程中保持不变
                //before = before++;
                before++;
            } else {
                after++;
                subList.add(after);
                add = add + after;
            }
        }
        return list;
    }
}

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

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值