输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
1,暴力法
枚举每个正整数为起点,判断以它为起点的序列和 sum 是否等于target 即可,由于题目要求序列长度至少大于 2 ,所以枚举的上界为 (target-1)/2
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>> res; //定义二维数组
vector<int>ans; //定义一维数组
int sum=0; //初始化求和变量
int limit = (target-1)/2; //设定上限值
for(int i=1;i<=limit;i++) //循环遍历
{
for(int j=i; j<target;j++)
{
sum+=j;
if(sum > target) //如果大于target,跳出循环
{
sum = 0;
break; //终止循环
}
else if(sum == target) //如果等于target,将外循环起点至内循环结束点加入一维数组
{
ans.clear();
for(int k=i;k<= j;k++)
{
ans.emplace_back(k);
}
res.emplace_back(ans); //将一维数组插入二维数组
sum = 0; //清空求和变量
break; //跳出循环,执行下一个外循环。
}
}
}
return res;
}
};
2,滑动窗口
将target看成一个等差排列的数组[1,2,3,4,5,6,7,8,9…],滑动窗口就是在数组中框选一部分,然后向右滑动。
我们设滑动窗口的左边界为 i,右边界为 j,则滑动窗口框起来的是一个**左闭右开区间 [i, j)**在一开始,i=1, j=1,滑动窗口位于序列的最左侧,窗口大小为零。
滑动窗口的重要性质是:窗口的左边界和右边界永远只能向右移动,而不能向左移动。
当滑动窗口的右边界向右移动时,也就是 j = j + 1,窗口中多了一个数字 j,窗口的和也就要加上 j。当滑动窗口的左边界向右移动时,也就是 i = i + 1,窗口中少了一个数字 i,窗口的和也就要减去 i
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
int i = 1; //定义滑动窗口的左边界
int j = 1; //定义滑动窗口的右边界
int sum = 0; //初始化累加和
vector<vector<int>> ans; //定义二维数组
while(i <= target/2)
{
if(sum < target) //如果sum>target,sum累加右边界值,并且右边界往右滑动一单位
{
sum += j;
j++;
}
else if(sum > target) //如果sum<target,sum减去左边界值,并且左边界向右滑动一单元
{
sum -= i;
i++;
}
else //如果sum=target
{
vector<int> nums; //定义一个一维数组
for(int k = i;k<j;k++) //循环遍历窗口
{
nums.push_back(k); //把每个数据插入nums数组
}
ans.push_back(nums); //把nums数组插入ans二维数组
sum = sum- 2*i - 1 ; //当sum==target时,左边界移动一单元必定无解,所以i要移动两个单位,sum也要减少相应两个单位对应的值
i+=2;
}
}
return ans;
}
};