题意
输入一个正整数 target
,输出所有和为 target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
注意:结果要是 连续的正整数序列 。所以,示例1中,返回的结果不能有 [1,8]、[2,7]....等,因为这些不是连续的序列。
解题思路—滑动窗口
对于这道题来说,数组就是正整数序列 [1,2,3,…,n]。我们设滑动窗口的左边界为 i,右边界为 j,则滑动窗口框起来的是一个左闭右开区间 [i, j)。
为了编程的方便,滑动窗口一般表示成一个左闭右开区间。在一开始,i=1, j=1,滑动窗口位于序列的最左侧,窗口大小为零。
在这道题中,我们关注的是滑动窗口中所有数的和。当滑动窗口的右边界向右移动时,也就是 j = j + 1,窗口中多了一个数字 j,窗口的和也就要加上 j。当滑动窗口的左边界向右移动时,也就是 i = i + 1,窗口中少了一个数字 i,窗口的和也就要减去 i。滑动窗口只有 右边界向右移动(扩大窗口) 和 左边界向右移动(缩小窗口) 两个操作,所以实际上非常简单。
C++实现
class Solution
{
public:
vector<vector<int>> findContinuousSequence(int target)
{
// i和j是滑动窗口的左右边界( [i,j) )
int i=1,j=1;
//滑动窗口内的和
int sum=0;
vector<vector<int>>res; //最终结果
//滑动窗口左边界最多只能到target的一半,因为再大的话,滑动窗口内的和就会超过target。
while(i<=(target/2))
{
//滑动窗口内的和大于target了,左边界就要向右移动,缩小窗口
if(sum>target)
{
sum-=i;
i++;
}
//滑动窗口内的和小于target了,右边界就要向右移动,增大窗口
else if(sum<target)
{
sum+=j;
j++;
}
//滑动窗口内的和等于target了,记录结果。并且左边界向右移动,
//看以下一个序列开头的窗口内的和能否等于target。
else
{
vector<int>tmp;
for(int k=i;k<j;k++)
{
tmp.emplace_back(k);
}
res.emplace_back(tmp);
sum-=i;
i++;
}
}
return res;
}
};