题目描述:找出所有和为S的连续正数序列
思路分析:(一)求出连续序列的中间值和长度。
因为是连续正数序列,所以实质上是一个公差为1的等差数列,可以利用等差数列的和来计算。
假设长度为n
(1)先算出中间值S/n,但要分以下两种情况:
当n为奇数时,序列的中间值正好是序列的平均值;
当n为偶数时,序列的中间两个数的平均值是序列的平均值。
(2)并且不用n不用从2计算到S,由等差数列的和为S=n*(n+1)/2 可以得到n和S的范围,具体如下图:
代码实现:
import java.util.ArrayList; public class Solution { public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { ArrayList<ArrayList<Integer>> array = new ArrayList<> (); for(int n= (int)Math.sqrt(2*sum);n>=2;n--) { if((n&1)==1&&sum%n==0||(sum%n)*2==n) { ArrayList<Integer> list = new ArrayList<Integer>(); for(int i = 0,k=(sum/n)-(n-1)/2;i<n;i++,k++) { list.add(k); } array.add(list); } } return array; } }
(二)利用滑动窗口设置双指针的形式来调整,并且用到了等差数列求和的第二个公式S=(a1+an)*n/2;
分别设置两个变量plow,phigh来表示滑动窗口的两端,如果当前窗口中数的和比sum的小,则需要右边窗口左移,也就是phigh++,如果比sum大,则需要左边窗口右移,也就是plow++;
代码如下:
import java.util.ArrayList; public class Solution { public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { ArrayList<ArrayList<Integer>> array = new ArrayList<> (); int plow=1,phigh=2; while(plow<phigh) { int cur = (plow+phigh)*(phigh-plow+1)/2; if(cur==sum) { ArrayList<Integer> list = new ArrayList<Integer>(); for(int i=plow;i<=phigh;i++) { list.add(i); } array.add(list); plow++; }else if(cur>sum) { plow++; }else { phigh++; } } return array; } }
反思:以上这个滑动窗口的方法很巧妙,可以对其进行扩展,如果不是连续的数列但也是等差数列,也可以利用这个方法,关键就是指针的移动。而且要注意的是列表里存储的还是一个列表项。