[剑指offer]和为s的连续正数序列
题目描述
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
解题思路
- 滑动窗口
- 滑动窗口可以看做数组中框起来的一部分,这道题中数组就是[1,2,3,4,5,6,7,8,9,……,n],我们设滑动窗口的左边界为left,右边界为right,滑动窗口为[left,right],初始为left=1,right=1;
- sum为滑动窗口的和,初始为1,当sum<target时,窗口的和需要增加,所以要扩大窗口,right++;当sum>targe时,窗口的和需要减少,所以要缩小窗口,left++;当sum=target,我们需要记录这个窗口,假如此时为[leftright],那么我们已经找到了left开头的唯一序列,接下来我们需要找left+1开头的序列,所以此时需要left++。
实现代码
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>>res;
int left=1,right=1;
int sum=1;
while(left<=target/2){//简单的说就是两个大于target/2的数相加一定大于target
//比如target=15时
//用暴力搜索的话,left最大到7就可以找到所以结果,当left=8时,满足条件的序列为[8,7],这个序列已经在left=7时就找到了
//用滑动窗口的话,当left=8时,right只能载left的右边取比8大的值,和就一定大于15了
if(sum<target){
right++;
sum+=right;
}
else if(sum>target){
sum-=left;
left++;
}
else{
vector<int>tmp;
for(int i=left;i<=right;i++)
tmp.push_back(i);
res.push_back(tmp);
sum-=left;
left++;
}
}
return res;
}
};