剑指offer:和为S的连续正数序列
题意描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
解题思路
一、思路一
- 使用两个移动指针,low指针指向1,high指针指向2
- 计算两个指针之间的累加和,由于是连续的,差为1的一个序列,那么求和公式是(a0+an)*n/2
- 如果累加和与结果不符,移动指针。累加和与结果相符,加入list集合
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(sum <= 0) return res;
int low = 1;
int high = 2;
while(low < high){ //当两个指针相遇时,之后的累加和大于输入,跳出循环
int cur = (low + high) * (high-low+1) / 2;
if(cur == sum){ //累加和符合输入输入
ArrayList<Integer> list = new ArrayList<>();
//【low,high】之间的数加入list集合
for(int i=low;i<=high;i++){
list.add(i);
}
res.add(list);
low++; //移动low指针,寻找下一个
}else if(cur < sum){
high ++;
}else{
low ++;
}
}
return res;
}
}
二、思路二
- 若[begin, end]之和 > S,从序列中去掉第一个值(增大begin)
- 若和 < S,增大end,和中加入新的end
- 等于S,将[begin, end] 纳入到结果集中
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
ArrayList<ArrayList<Integer>> res = new ArrayList<>();
if(sum < 3) return res; //sum最小为3
int begin = 1;int end = 2;
int cur = begin + end;
int mid = (sum + 1) >> 1;
while(begin < mid){ //当begin 》= mid时,最小的累加和也大于sum
while(cur > sum){ //当退出循环时,cur》=sum
cur -= begin; //cur 》sum,放弃最小值
begin ++; //移动左指针
}
if(sum == cur && begin < end){ //防止出现数组只有一项的情况
ArrayList<Integer> list = new ArrayList<>();
for(int i=begin;i<=end;i++){
list.add(i);
}
res.add(list);
}
end ++; //①cur《sum,移动右指针 ②已经找到一组,移动右指针找下一组
cur += end;
}
return res;
}
}
三、思路三
其他思路推荐阅读下面这篇博客

浙公网安备 33010602011771号