剑指 Offer 57 - II. 和为s的连续正数序列
输入一个正整数 target
,输出所有和为 target
的连续正整数序列(至少含有两个数)。
序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。
示例 1:
输入: target = 9
输出: [[2,3,4],[4,5]]
示例 2:
输入: target = 15
输出: [[1,2,3,4,5],[4,5,6],[7,8]]
限制:
1 <= target <= 10^5
解题思路
由于序列是严格递增的正整数序列,所以我们可以用双指针算法
。
-
设置两个指针
i
和j
,分别指向连续正数序列的起始和终止 -
用
sum
表示当前连续正数序列的和,即sum=i+(i+1)+…+j
-
以
i
递增的方式遍历整个序列(1到target
),代表查找以i
开头的时候结尾j
应该是多少,i~j
的和sum
才不会小于target
。所以当sum < target
时说明j
应该往后移动,当sum = target
时,说明满足题意,记录一个结果,当sum > target
时说明以当前i
开头的连续正数序列之和不可能等于target
,可以去计算下一个以i
开头的连续正数序列了。
Java代码
class Solution {
public int[][] findContinuousSequence(int target) {
//一开始并不知道结果数组中会有多少了结果,即不知道结果数组的长度,因此先用List
List<int[]> list = new ArrayList<>();
int sum = 1;//i从1开始,所以sum起始是1
for(int i = 1,j = 1; i < target;i++){
while(sum < target) {//j后移到哪个位置时,才能i + (i+1) +... +j >= target
j++;
sum += j;
}
if(sum == target && j - i > 0){//j - i > 0是题目要求的至少要含两个数
int[] temp = new int[j - i + 1];
for(int p = 0,q = i; q <= j; p ++ ,q++){
temp[p] = q;
}
list.add(temp);
}
sum -= i;//当前i移出,计算下一个以i+1开头的正数序列去
}
//C++中没有不规则数组,故必须指定第二维的大小
//Java中第二维不写,则说明创建了一个不规则数组(Java核心技术卷I,p89)
int[][] res = new int[list.size()][];
for(int i = 0;i < list.size();i++){
res[i] = list.get(i);
}
return res;
}
}