• 剑指41.和为S的连续正数序列


    题目描述

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

    输出描述:

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

    思路

    思路1:滑动窗口法(区间连续,双指针同向移动)。用两个数small和big分别表示序列的最小值和最大值,首先把small初始化为1,big初始化为2.如果从small到big的序列的和大于s,则从序列中去掉较小的值,也就是增大small的值。如果从small到big的序列的和小于s,则可以增大big,让这个序列包含更多的数字。因为这个序列至少要有两个数字,我们一直增加small到(1+s)/2为止。

     

    思路2:还可以尝试数学分析法。

    解法1

    import java.util.ArrayList;
    public class Solution {
        // 版本1
        public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
            ArrayList<ArrayList<Integer> >  res = new ArrayList<>();
            int small = 1, big = 2;  //两个起点,相当于动态窗口的两边
            while (small < big){ // small < (sum + 1) / 2  也能通过
                int tempSum = (small + big)*(big - small + 1) / 2;
                if (tempSum == sum){
                    ArrayList<Integer> list = new ArrayList<>(); // 每次用的时候new一个,这样就不需要用完list.clear()了
                    for (int i = small; i <= big; i++) {
                        list.add(i);
                    }
                    res.add(list);
                    big++;
                }else if (tempSum > sum){  //如果当前窗口内的值之和大于sum,那么左边窗口右移一下
                    small++;
                }else{  //如果当前窗口内的值之和小于sum,那么右边窗口右移一下
                    big++;
                }
            }
            return res;
        }
        // 版本2
        // 与版本1相比不同之处:求连续序列的和,因此可以在前一个序列和的基础上求操作之后的序列的和。
        public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
            ArrayList<ArrayList<Integer> >  res = new ArrayList<>();
            int small = 1, big = 2;  //两个起点,相当于动态窗口的两边
            int tempSum = small + big;
            while (small < big){ // small < (sum + 1) / 2  也能通过
                if (tempSum == sum){
                    ArrayList<Integer> list = new ArrayList<>();
                    for (int i = small; i <= big; i++) {
                        list.add(i);
                    }
                    res.add(list);
                    big++;
                    tempSum += big;
                }else if (tempSum > sum){  //如果当前窗口内的值之和大于sum,那么左边窗口右移一下
                    tempSum -= small;
                    small++;
                }else{  //如果当前窗口内的值之和小于sum,那么右边窗口右移一下
                    big++;
                    tempSum += big;
                }
            }
            return res;
        }
    }

    Note: while循环条件最好用 small < (sum+1)/2 这样可以提前结束。

    解法2

    M一下,以后再做可以试试用数学的思路解一下。

    自己写的暴力遍历法

    import java.util.ArrayList;
    public class Solution {
        // 思路就是根据等差数列求和公式(count*(a1+an))/2,遍历起始位置a1,然后遍历count,看是否满足题意
        // 测试用例,输入15;输出1~5 、4~6 、7~8
        public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
            ArrayList<ArrayList<Integer> > res = new ArrayList<>();
            ArrayList<Integer> list = new ArrayList<>();
            for (int i = 1; i <= sum / 2 + 1; i++) {
                int num = i;
                int counts = sum / 2 + 1;
                while (counts >= 2){
                    if (counts*(num+num+counts-1)/2 == sum){  // 核心
                        for (int j = num; j <=num+counts-1;j++)
                            list.add(j);
                        res.add(new ArrayList<>(list));
                        list.clear();
                        break;
                    }
                    counts--;
                }
            }
            return res;
        }
    }

    收获

    如果需要多次使用ArrayList添加数据,可以在每次用的时候new一个新的,这样就不用共用一个,用完list.clear()了。

  • 相关阅读:
    JS中 try...catch...finally (转)
    Npm基本指令(转)
    常用Dos(转)
    理解Node.js异步非阻塞I/O与传统线性阻塞IO的区别(转)
    Java 连接 Access数据库方式
    感知器-从零开始学深度学习
    Oracle的SQL语句中如何处理‘&’符号
    (转)远程桌面超出最大连接数怎么办
    url中含有%
    (转)silverlight应用程序中未处理的错误代码:2104 类别:InitializeError
  • 原文地址:https://www.cnblogs.com/HuangYJ/p/13559983.html
Copyright © 2020-2023  润新知