此题出自牛客网的剑指offer专题
题目描述
小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序
解题思路
使用双指针技术,就是相当于有一个窗口,窗口的左右两边就是两个指针,我们根据窗口内值之和来确定窗口的位置和宽度。
实现代码
Java版本
import java.util.ArrayList;
public class Solution {
public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) {
//用来存放结果集
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
//用来存放每一次得到的结果
ArrayList<Integer> list = new ArrayList<>();
// 如果和小于3(意味着序列的数目小于2),直接返回
if(sum<3){
return result;
}
//定义两个变量用作指针
int pLow = 1,pHigh = 2;
while(pLow<pHigh){
//由于是连续,差为1的序列,所以可以运用等差数列的求和公式(a0+an)*n/2
int cur = (pLow+pHigh)*(pHigh-pLow+1)/2;//这里利用了位运算
//如果此时cur变量与sum相等,则说明已经找到一个符合要求的序列
if(cur==sum){
//将序列中的数字全添加到list中
for(int i=pLow;i<=pHigh;i++){
list.add(i);
}
//添加到结果集中
result.add(new ArrayList<Integer>(list));
//list清空以便下次使用
list.clear();
//低位指针加一
pLow++;
}
//如果cur值比sum值大,由于该序列为递增序列,所以此时窗口应该缩小即pLow指针需向前一步
else if(cur>sum){
pLow++;
}
//如果cur值比sum值小,由于该序列为递增序列,所以此时窗口应该缩小即pHigh指针需向前一步
else if(cur<sum){
pHigh++;
}
}
return result;
}
}
C++版本
class Solution {
public:
vector<vector<int> > FindContinuousSequence(int sum) {
vector<vector<int>> result;
if(sum<3)
{
return result;
}
int pLow=1,pHigh=2;
while(pLow<pHigh)
{
int cur = (pLow+pHigh)*(pHigh-pLow+1)>>1;
if(cur==sum)
{
vector<int> list;
for(int i=pLow;i<=pHigh;i++)
{
list.push_back(i);
}
result.push_back(list);
pLow++;
}
else if(cur>sum)//缩小窗口
{
pLow++;
}
else//增大窗口
{
pHigh++;
}
}
return result;
}
};