题目
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9 输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15 输出:[[1,2,3,4,5],[4,5,6],[7,8]]
解法一 滑动窗口
其实滑动窗口就是一直维护一个窗口,通过控制这个窗口的起始点和结束点的位置,来更改得到的值。比如这题,我们从最开始滑动,如果当前窗口内的值小于target,我们则把窗口的结束点向左移动,反之如果大于,则我们需要移除右边的,这样,我们的窗口会从队头扫描到队尾,把所有符合条件的连续数组都给记录下来。
这里最外部的while循环为 left<=target/2的原因是,因为最右边的数right最小的情况下也为left,那我们需要满足最极限的情况,即left+right = left + left <= target, 则可以得到left <= target/2。
class Solution {
public int[][] findContinuousSequence(int target) {
// 最开始的时候默认左边界和右边界均为1起始
int left = 1;
int right = 1;
List<int[]> result = new ArrayList<>();
// 一直储存着现在这个窗口内所有数字的和
int sum = 0;
while(left <= target /2){
// 当现在的和小于目标时,我们需要把窗口向右边扩大一位
if(sum < target){
sum += right;
right ++;
// 当现在的和大于目标时,我们需要把窗口最左边一位的移除
}else if(sum > target){
sum -= left;
left ++;
// 当和等于目标时,我们把窗口的现在的数储存起来,同时把最左边的两个数移除
}else{
int[] temp = new int[right-left];
for(int i = left; i < right; i++){
temp[i-left] = i;
}
result.add(temp);
// 为什么要移除最左边的两个数呢,因为我们的目的是把整个窗口滑到最右边,
// 下一步一定是向最右扩张,而此时我们的值已经等于target了,而最左边的
// 第一位一定比向右扩张的小,最左边只移除一位的话,还是一定大于target,
// 只有再移除最左边的第二位才能保证此时sum可能小于target
sum -= left+left+1;
left += 2;
}
}
return result.toArray(new int[result.size()][]);
}
}
时间复杂度:O(target) 空间复杂度:O(1)