题目描述:
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
例如输入:
输入:target = 9
输出:[[2,3,4],[4,5]]
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
数据范围:
1 <= target <= 10^5
解题思路:
尺取法:顾名思义,像尺子一样取一段,借用挑战书上面的话说,尺取法通常是对数组保存一对下标,即所选取的区
间的左右端点,然后根据实际情况不断地推进区间左右端点以得出答案。之所以需要掌握这个技巧,是因为尺取法比
直接暴力枚举区间效率高很多,尤其是数据量大的。
但是尺取法有他的适用情况
- 要求一个连续区间
- 有一个总的标准,比如说,连续区间求和满足一个值sum,求一个连续区间内的xx种类
- 区间长度是弹性的,在满足标准的情况下,推进左右端点,使得区间长度符合要求.
回过头看此题是否满足尺取法的要求呢
- 连续的正整数序列
- 标准:正整数序列和满足 target
- 区间长度是弹性的
Yes! 满足要求,接下来看算法的流程
算法流程: - 初始化三个变量 i = 1 表示头指针, j = 2 表示尾指针,sum = 1和一个动态数组(vector)tmp.
- 进入循环
- 如果 i < j (头指针小于尾指针) 且 sum < target (求和不等于target的值)循环执行
- sum += j (sum加上尾指针的值)
- tmp加入j (序列加上尾指针的值)
- j+=1 (尾指针后移一位)
- 如果i >=j(头指针大于等于尾指针)
结束整个循环 - 如果 sum 等于 target
- 判断此时tmp的大小,满足大于等于2的话,最后结果集加入此序列
- tmp删除头指针的值
- sum-=头指针的值
- 头指针后移一位
总的来说,就像一条毛毛虫
演示一下题目给的用例。
- 如果 i < j (头指针小于尾指针) 且 sum < target (求和不等于target的值)循环执行
AC代码(c++)
class Solution {
public:
vector<vector<int> > findContinuousSequence(int target) {
vector<vector<int> > arr;
vector<int> tmp;
int i=1,j=2;
int sum = 1;
tmp.push_back(1);
while(1){
while(i<j && sum<target){
sum+=j;
tmp.push_back(j);
j++;
}
if(i>=j)
break;
if(sum==target)
{
if(tmp.size()>=2){
arr.push_back(tmp);
}
tmp.erase(tmp.begin());
sum-=i;
i++;
}
while(sum>target){
sum-=i;
i++;
tmp.erase(tmp.begin());
}
}
return arr;
}
};