题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列?
分析
有两种方法可解此题
1.双指针法
规定一个窗口,窗口左右两边是两个指针,根据窗口内值的和来确定窗口的位置和长度。若当前窗口内和小于S,右指针右移一位,若大于S则左指针右移一位,若等于S则将窗口内的值保存到一个list中,并将左指针右移一位,重新开始,走到左指针超过右指针。
2.当n为奇数时,序列的中数正好是序列的均值即,则。当n为偶数时均值为中间两个数的均值,这个平均值的小数部分为0.5,则。由等差求和可知。所以遍历2~之间n的值。中间值为,起始值为。
代码
import java.util.ArrayList;
public class ContinualSum {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList<ArrayList<Integer>> res = fun2(50);
for(ArrayList<Integer> list: res){
for(int num: list){
System.out.print(num+",");
}
System.out.println();
}
}
public static ArrayList<ArrayList<Integer>> fun1(int sum){
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
int plow=1;
int phigh=2;
while(plow<phigh){
int cur = (phigh+plow)*(phigh-plow+1)/2;
if(cur == sum){
ArrayList<Integer> list = new ArrayList<>();
for(int i=plow; i<=phigh; i++){
list.add(i);
}
res.add(list);
plow++;
}else if(cur<sum){
phigh++;
}else{
plow++;
}
}
return res;
}
public static ArrayList<ArrayList<Integer>> fun2(int sum){
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
int n=(int) Math.sqrt(2*sum);
for(; n>=2; n--){
if((n & 1)==1 && sum % n==0 || (sum%n)*2==n){
ArrayList<Integer> list = new ArrayList<>();
//j是开始值
for(int i=0, j=(sum/n)-(n-1)/2; i<n; i++, j++){
list.add(j);
}
res.add(list);
}
}
return res;
}
}