题目描述

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

输出描述:

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

 

 

题目链接:

https://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe?tpId=13&tqId=11194&rp=1&ru=/activity/oj&qru=/ta/coding-interviews/question-ranking

 

分析:

移动窗口。

左边界left,右边界right,当前和curSum。

大于sum,当前和减去左边数值,left++。

小于sum,当前和增加右边数值,right++。

 

结束条件,right最大值是 sum/2+1。

(写法中由于每次右移后+1,所以判断时right<mid +1)

 

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
        ArrayList<ArrayList<Integer>> list = new ArrayList<>();
        if(sum<=1){
            return list;
        }
        int mid = sum/2+1;
        int left = 1;
        int right = 2;
        //记录当前和
        int curSum = 1;
        //结束条件,left最大是mid-1,right最大是mid,因为每次右移后有right++操作,所有判断right <= mid+1
        while(right <= mid + 1){
            //小于目标和时,右边界往右移动,并添加到当前和上
            if(curSum<sum){
                curSum+=right;
                right++;
            }else if(curSum>sum){
                //当大于目标和时,左边界向右移动,减去最左边的值
                curSum-=left;
                left++;
            }else{
                //当前和与目标和相同时,一个答案
                ArrayList<Integer> tmp = new ArrayList<>();
                for(int i=left;i<right;i++){
                    tmp.add(i);
                }
                list.add(tmp);
                //答案记录完后,右边界向右边移动
                curSum +=right;
                right++;
            }
            
        }
        return list;
    }
}

 

 

方法2详见:

https://www.nowcoder.com/profile/645151/codeBookDetail?submissionId=1519890

 

分析:以 连续正数的数量 i  为突破点。

根据等差数列的求和公式: S = (1 + n) * n / 2,得到.,所以遍历区间:[2 ,2S的开方]

根据连续数量判断是否存在相应的区间,使该区间的和等于目标和sum。

  1、连续数量len为 奇数。可知 i * mid = sum ,所以有 sum%i  == 0。(mid为连续序列的平均值即中间值)

  2、连续数量len为 偶数。 [a+0,a+1,a+2……a+i-1]的和对  i  取余 ,不难看出只需求[0,1,2 ……,i-1 ]的和对 i 取余,结果为  ( i - 1)/2,因为 i 为偶数,所以 i/2 == (i-1)/2,  所以sum % i *2 = i。。 例: a + 0,a + 1,a + 2, a + 3  可知,(4*a + (0+ 3)/2  *  4) % 4 = 2。

知道 i 连续正数的数量存在相应区间,求区间位置。

 i  *  mid  = sum,所以mid   = sum / i,找到中间值, 减去(i-1)/2找到左边界。所以有  (sum/i) - (i-1)/2


 

 

 

 

import java.util.ArrayList;
public class Solution {
    public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
       
        ArrayList<ArrayList<Integer>> list = new ArrayList<>();
        for(int i = (int)Math.sqrt(2*sum);i >=2;i--){
            if((i&1)==1&&sum%i==0||sum%i*2==i){
                ArrayList<Integer> tmp = new ArrayList<>();
                for(int j=(sum/i) - (i-1)/2,k=0;k<i;k++,j++){
                    tmp.add(j);
                }
                list.add(tmp);
            }
        }
        return list;
    }
}

 

posted on 2020-06-09 14:34  MoonBeautiful  阅读(128)  评论(0编辑  收藏  举报