剑指offer:和为S的连续正数序列

题意描述

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

输出描述

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

解题思路

一、思路一

  • 使用两个移动指针,low指针指向1,high指针指向2
  • 计算两个指针之间的累加和,由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2
  • 如果累加和与结果不符,移动指针。累加和与结果相符,加入list集合
    import java.util.ArrayList;
    public class Solution {
        public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
           ArrayList<ArrayList<Integer>> res = new ArrayList<>();
           if(sum <= 0) return res;
            int low = 1;
            int high = 2;
            while(low < high){	//当两个指针相遇时,之后的累加和大于输入,跳出循环
                int cur = (low + high) * (high-low+1) / 2;
                if(cur == sum){	//累加和符合输入输入
                    ArrayList<Integer> list = new ArrayList<>();
                    //【low,high】之间的数加入list集合
                    for(int i=low;i<=high;i++){
                        list.add(i);
                    }
                    res.add(list);
                    low++;	//移动low指针,寻找下一个
                }else if(cur < sum){
                    high ++;
                }else{
                    low ++;
                }
            }
            return res;
        }
    }

二、思路二

  • 若[begin, end]之和 > S,从序列中去掉第一个值(增大begin)
  • 若和 < S,增大end,和中加入新的end
  • 等于S,将[begin, end] 纳入到结果集中
    import java.util.ArrayList;
    public class Solution {
        public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
           ArrayList<ArrayList<Integer>> res = new ArrayList<>();
           if(sum < 3) return res; //sum最小为3
            int begin = 1;int end = 2;
            int cur = begin + end;	
            int mid = (sum + 1) >> 1;
            while(begin < mid){	//当begin 》= mid时,最小的累加和也大于sum
                while(cur > sum){	//当退出循环时,cur》=sum
                    cur -= begin;	//cur 》sum,放弃最小值
                    begin ++;	//移动左指针
                }
                if(sum == cur && begin < end){	//防止出现数组只有一项的情况
                    ArrayList<Integer> list = new ArrayList<>();
                    for(int i=begin;i<=end;i++){
                        list.add(i);
                    }
                    res.add(list);
                }
                end ++;	//①cur《sum,移动右指针 ②已经找到一组,移动右指针找下一组
                cur += end;
            }
            return res;
        }
    }

三、思路三

其他思路推荐阅读下面这篇博客

和为S的连续正数序列

posted @ 2020-05-07 22:16  灵图  阅读(111)  评论(0)    收藏  举报