剑指offer58_和为S的连续正数序列
和为S的连续正数序列
输入一个非负整数 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]]
算法思路
滑动窗口(双指针):
- 初始化两个指针i和j都指向1,s记录当前窗口内数字的和(初始为1)
- 外层循环移动窗口左边界i:
- 内层循环移动窗口右边界j,直到窗口内和s >= sum
- 如果s等于sum且序列长度大于1,则记录该序列
- 每次外层循环后,减去左边界的值(i),移动左边界
- 时间复杂度:O(n),其中n为sum值。虽然有两层循环,但每个元素最多被访问两次(被i和j各访问一次)
- 空间复杂度:O(1),除了存储结果的res外,只使用了常数空间
class Solution {
public:vector<vector<int>> findContinuousSequence(int sum) {vector<vector<int>> res; // 存储结果if(!sum) return res; // 处理sum为0的特殊情况// 使用滑动窗口,i为左边界,j为右边界,s为当前窗口和for(int i = 1, j = 1, s = 1; i < sum; i ++){// 移动右边界直到和>=sumwhile(s < sum) s += ++j;// 如果和等于sum且序列长度大于1if(s == sum && j - i + 1 > 1){vector<int> line;// 生成当前序列for(int k = i; k <= j; k ++) line.push_back(k);res.push_back(line);}s -= i; // 移动左边界前减去左边界的值}return res;}
};
实例演示
示例1:sum = 9
输出:
[[2, 3, 4],[4, 5]
]
解释:
- 2 + 3 + 4 = 9
- 4 + 5 = 9
示例2:sum = 15
输出:
[[1, 2, 3, 4, 5],[4, 5, 6],[7, 8]
]
解释:
- 1 + 2 + 3 + 4 + 5 = 15
- 4 + 5 + 6 = 15
- 7 + 8 = 15
示例3:sum = 100
输出:
[[9, 10, 11, 12, 13, 14, 15, 16],[18, 19, 20, 21, 22],[30, 31, 32],[50, 51]
]
解释:
- 9到16的和为100
- 18到22的和为100
- 30到32的和为100
- 50+51=100