✍个人博客:https://blog.csdn.net/Newin2020?spm=1011.2415.3001.5343
📚专栏地址:剑指offer系列题解
📝原题地址:题目地址
📣专栏定位:为找工作的小伙伴整理常考算法题解,祝大家都能成功上岸!
❤️如果有收获的话,欢迎点赞👍收藏📁,您的支持就是我创作的最大动力💪
题目描述
输入一个非负整数 S,打印出所有和为 S 的连续正数序列(至少含有两个数)。
例如输入 15,由于 1+2+3+4+5=4+5+6=7+8=15,所以结果打印出 3 个连续序列 1∼5、4∼6 和 7∼8。
数据范围
0≤S≤1000
样例
输入:15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
方法一:双指针 O(sum)
这道题可以用双指针的思想来做,具体步骤如下:
- 设置两个指针
i
和j
,分别往后进行遍历,而s
记录的是从i
到j
的和。 - 只要
s
是小于sum
的就将j
往后加1
并加上它。 - 如果
s
等于sum
,则将i
到j
的所有数加入数组当中。 j
不用往前移,只用将s
减去i
即可。这是因为将s
减去i
后是一定比sum
要小的,这就类似于一个滑动窗口,不断的调整首尾两个边界。
我们来看个例子,就拿题目样例举例,假设给定的 sum
为 15
:
第一轮: j
一直往后移动,直至 i
和 j
之间元素之和大于等于 15
。
此时 s
为 15
,故 [1,2,3,4,5]
是一组答案,然后使 i
往后移一位,减小 sum
的值。
第二轮: j
继续往后移,直至 i
和 j
之间元素之和大于等于 15
。
发现已经超过 15
,故将 i
往后移一位。
第三轮: 因为上一轮 i
移动后 s
已经等于 15
,故 j
无需后移,而 [4,5,6]
是一组答案,然后将 i
继续往后一位。
第四轮: j
继续后移,直至 i
和 j
之间元素之和大于等于 15
。
此时 s
已经大于 15
,故直接将 i
后移一位。
第五轮: j
继续后移,直至 i
和 j
之间元素之和大于等于 15
。
此时 s
等于 15
,故 [6,7,8]
也是一组答案,然后再将 i
继续后移一位。
第六轮: j
继续后移,直至 i
和 j
之间元素之和大于等于 15
。
sum
已经大于 15
,故 i
继续往后移一位。
此时 i
已经大于 sum/2
,故直接退出返回最终答案。
这里之所以以 i <= sum/2
为结束标志,是因为连续序列的答案中下边界最大也不可能超过 sum/2
。比如 15
的 sum/2
等于 7
,故有一个连续序列 [7,8]
的答案,但不会出现 [8,8]
的情况,并且 [8,9]
已经大于 sum
了。再比如 16
的 sum/2
等于 8
,而 [8,9]
已经大于 16
了,下边界再增加也没有用。
class Solution {
public:
vector<vector<int> > findContinuousSequence(int sum) {
vector<vector<int>> ans;
for (int i = 1, j = 1, s = 1; i <= sum / 2; i++)
{
while (s < sum) j++, s += j;
if (s == sum && j > i)
{
vector<int> temp;
for (int k = i; k <= j; k++) temp.push_back(k);
ans.push_back(temp);
}
s -= i;
}
return ans;
}
};
欢迎大家在评论区交流~