输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入:target = 9
输出:[[2,3,4],[4,5]]
解析:看到本题,我相信大部分人都能想到并实现普通的暴力解法:
1)从1到target开始遍历每一个数,将每一个数都假设作为满足条件的连续整数序列的起始元素,来进行逐个验证是否满足假设。
2)写函数来验证假设。在函数内部,就是从当前值出发,进行叠加,如果能有叠加值正好等于target,那就返回true,说明该值可以作为满足条件的连续整数序列起始值。否则返回false。
3)我们利用第二步中函数返回值作为判断依据,如果返回值false,则直接进行下一次循环,如果返回是true,则开始声明列表,将从该值起,一直到累加和为target为止,所有的数添加到列表中。再将该小列表添加到大列表中。
4)将大列表转化为数组即可返回。
class Solution {
ArrayList<ArrayList<Integer>> result = new ArrayList<>();
public int[][] findContinuousSequence(int target) {
for(int i = 1; i < target; i++){
if(Test(i, target)){
ArrayList<Integer> li = new ArrayList<>();
int sum = 0;
for(int j = i; j < target; j++){
sum += j;
li.add(j);
if(sum == target){
break;
}
}
result.add(li);
}
}
int[][] re = new int[result.size()][];
for(int i = 0; i < result.size(); i++){
re[i] = new int[result.get(i).size()];
for(int j = 0; j < result.get(i).size(); j++){
re[i][j] = result.get(i).get(j);
}
}
return re;
}
boolean Test(int k, int target){
int sum = 0;
int i = 0;
for(i = k; i < target; i++){
sum += i;
if(sum == target){
return true;
}
if(sum > target){
return false;
}
}
return false;
}
}
下面我们来看第二种:滑动窗口。
只要是跟连续数组相关的,滑动窗口一定要能联系到。我们从1开始进行滑动。如果窗口内值小于target,则窗口右侧增加数据。如果窗口内值大于target,则窗口左侧减少数据。如果正好相等,则就要将窗口内值保存到list中,再放入大list内。一直滑动到结束为止。
public int[][] findContinuousSequence(int target) {
int i = 1; // 滑动窗口的左边界
int j = 1; // 滑动窗口的右边界
int sum = 0; // 滑动窗口中数字的和
List<int[]> res = new ArrayList<>();
while (i <= target / 2) {
if (sum < target) {
// 右边界向右移动
sum += j;
j++;
} else if (sum > target) {
// 左边界向右移动
sum -= i;
i++;
} else {
// 记录结果
int[] arr = new int[j-i];
for (int k = i; k < j; k++) {
arr[k-i] = k;
}
res.add(arr);
// 左边界向右移动
sum -= i;
i++;
}
}
return res.toArray(new int[res.size()][]);
}