剑指offer-和为S的连续正数序列
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
思路
思路一:
直接通过等差数列的求和公式.枚举序列的第一个元素,设第一个元素为h,最后一个元素为t,和为s
那么会有$(h+t)(t-h+1)/2 = 2s$
因此可求出t解,再用求和公式验证一遍,如果验证成功,则说明这段序列满足,否则继续枚举
思路二:
剑指offer上的思路.
维护一个队列,如果队列的和小于sum,那么队尾添加新元素.否则,删除队头元素.
当队列和为sum时,此时队列中的元素序列满足条件.
code
// 思路一
public static ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
if(sum == 1) {
return lists;
}
int up = (int)Math.ceil(sum/2.0);
for (int h = 1; h <= up; h++) {
int delta = 1-4*h+4*h*h+8*sum;
if(delta < 0){
continue;
} else {
int t = (int)((-1+Math.sqrt(delta))/2);
int s = (h+t)*(t-h+1)/2;
if(s == sum) {
ArrayList<Integer> list = new ArrayList<>();
for (int i = h; i <= t ; i++) {
list.add(i);
}
lists.add(list);
}
}
}
return lists;
}
// 思路二
public static ArrayList<ArrayList<Integer> > FindContinuousSequence2(int sum) {
ArrayList<ArrayList<Integer>> lists = new ArrayList<>();
if(sum == 1) {
return lists;
}
int s = 0;
int up = (int)Math.ceil(sum/2.0);
Queue<Integer> queue = new LinkedList<>();
// 这里需要up+1次,来避免最后一次无法判断
for (int i = 1; i <= up+1;) {
if(s < sum) {
queue.offer(i);
s += i++;
} else if(s > sum) {
s -= queue.poll();
} else {
ArrayList<Integer> list = new ArrayList<>();
list.addAll(queue);
lists.add(list);
queue.offer(i);
s += i++;
}
}
return lists;
}