问题描述:
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
问题分析:
该问题是想要进行连续的正整数求和,并且和为指定的数。个人的思考是遍历所有小于该数的数,创建一个整数的集合用来存放连续的序列,创建一个存放整数集合的集合,最后将所有满足要求的正整数连续序列返回。
public static ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
if(sum==0){
return null;
}
//存储序列集合的集合
ArrayList<ArrayList<Integer>> listarr=new ArrayList<ArrayList<Integer>>();
int tmp=0;
for(int i=1;i<sum;i++){
//存储单个序列的集合
ArrayList<Integer> listint=new ArrayList<Integer>();
for(int j=i;j<sum;j++) {
listint.add(j);
tmp+=j;
if(tmp==sum){
tmp=0;
listarr.add(listint);
break;
}else if(tmp>sum) {
tmp=0;
listint.clear();
break;
}
}
}
return listarr;
}
方法二:该方法是讨论区的被采纳最多的方法,但是运行时间为27ms左右,上边我自己的程序运行时间为25ms左右,不知道怎么回事。。。求解
思路:设置一个窗口,窗口内连续的正整数之和为(n0+n1)n/2,相同时将序列加入集合并且将该集合加入集合中。若当前的和大于所给定的数时,说明窗口太大,左边的指针向右移,当前的和小于指定数时说明窗口太小,将右边指针向右移扩大窗。
public static ArrayList<ArrayList<Integer> > FindContinuousSequence2(int sum) {
int left=1;
int right=2;
ArrayList<ArrayList<Integer>> listarr=new ArrayList<ArrayList<Integer>>();
while(left<right) {
//任何连续的数窗口内的和为(右-左)*窗口长度/2
int cur=(right+left)*(right-left+1)/2;
ArrayList<Integer> listint=new ArrayList<Integer>();
if(cur==sum) {
for(int i=left;i<=right;i++) {
listint.add(i);
}
listarr.add(listint);
left++;
}else if(cur>sum) {
left++;
}else {
right++;
}
}
return listarr;
}