题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
思路
这些连续的正数序列,前后组成一对,一组之和是S的因子。 从连续序列的长度入手,长度记为i:
若长度是奇数,如果能整除S=100,说明S/i的结果就在连续序列的正中间,向前向后的数分别成组。如S=100,i=5,S/i=100/5=20,那么20是这个长度为5的序列中间数,19+21=40,18+22=40,这五个数组是一个连续序列。
若长度是偶数,即是有i/2个组,若S能整除组数,并且每组数值之和为奇数,那么可以组成连续序列。
满足的例子:长度i=8,有4组,每组和为25。那么这个序列的中间数可以看成是25/2=12(实质上是12和13)。另外三组也可向前向后成组。
不满足的例子:长度i=10,有5组,每组和为20,是不符合条件的,因为找不到这个中间数(10才是中间数,但只有这一个)另外,不需要遍历从2到S的数,因为序列长度到达某个位置,就算符合条件也不能找到足够数量的正整数了。如S=100,i=40,一共20组每组之和为5,但是5/2之前只有2个数了!
时间复杂度
O(n*sqrt(n)
代码
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<ArrayList<Integer>>();
for(int i=(int)Math.sqrt(sum*2);i>1;i--){
if( i % 2==1 && sum%i == 0 ){//长度是奇数,并且sum/i为整数,说明存在存在
ArrayList<Integer> list = new ArrayList<Integer>();
int k = sum/i;
for(int j=k-i/2;j<=k+i/2;j++)
list.add(j);
lists.add(list);
}
if( i % 2==0 && sum%(i/2) ==0 && (sum/(i/2))%2 ==1 ){
//长度是偶数,有i/2组,sum/组数 是奇数,说明存在
ArrayList<Integer> list = new ArrayList<Integer>();
int k = sum/i;
for(int j=k-i/2+1; j<=k+i/2; j++)
list.add(j);
lists.add(list);
}
}
return lists;
}
}