描述:
输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
示例 2:
输入:target = 15
输出:[[1,2,3,4,5],[4,5,6],[7,8]]
思路:
最容易想到的就是暴力解法,两层遍历。但是题目要求返回二维数组,这个不知道怎么定义,看下官方解析,定义如下:
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> vec = new ArrayList<int[]>();
// (target - 1) / 2 等效于 target / 2 下取整
int sum = 0, limit = (target - 1) / 2;
for (int i = 1; i <= limit; ++i) { //第一层循环
for (int j = i;; ++j) { //第二层循环:没有大小的限定条件
sum += j;
if (sum > target) {
sum = 0;
break;
} else if (sum == target) {
int[] res = new int[j - i + 1];
for (int k = i; k <= j; ++k) { //遍历后放入数组中
res[k - i] = k;
}
vec.add(res);
sum = 0;
break;
}
}
}
return vec.toArray(new int[vec.size()][]); //转为数组输出
}
}
第二种思路:
参考:https://leetcode-cn.com/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/solution/shi-yao-shi-hua-dong-chuang-kou-yi-ji-ru-he-yong-h/
使用滑动窗口:滑动窗口的左边界和右边界永远只能向右移动。
所以有以下几种情况:
- 窗口和 < target,窗口和需要变得更大,所以扩大窗口,窗口右边界向右移动;
- 窗口和 > target,窗口和需要变得更小,所以缩小窗口,窗口左边界向右移动;
- 窗口和 = target,记录结果,然后向后继续寻找,所以窗口的左边界向右移动;
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> res = new ArrayList<>();
int i = 1,j = 1,sum = 0; //i是窗口左边界,j是窗口右边界
while(i <= target / 2){
if(sum < target){ //当小于target时,窗口右边界右移
sum += j;
j++;
}else if(sum > target){ //当大于target时,窗口左边界右移
sum -= i;
i++;
}else if(sum == target){
int[] temp = new int[j - i]; //右边界是开区间
for(int k = i;k < j; k++){
temp[k - i] = k;
}
res.add(temp); //向后遍历
sum -= i;
i++;
}
}
return res.toArray(new int[res.size()][]);
}
}