这是我参与11月更文挑战的第26天,活动详情查看:2021最后一次更文挑战
和为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
题解
方法一:滑动窗口——Java
设连续正整数序列的左边界 i 和右边界 j ,则可构建滑动窗口从左向右滑动。循环中,每轮判断滑动窗口内元素和与目标值 target 的大小关系,若相等则记录结果,若大于 target 则移动左边界 i (以减小窗口内的元素和),若小于 target 则移动右边界 j (以增大窗口内的元素和)。
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> res = new ArrayList<>();
int left = 1;
int right = 2;
int sum = 3;
while (left < right) {
if (sum == target) {
int[] arr = new int[right - left + 1];
for (int i = left; i <= right; i++) {
arr[i - left] = i;
}
res.add(arr);
sum -= left;
left++;
} else if (sum < target) {
right++;
sum += right;
} else {
sum -= left;
left++;
}
}
return res.toArray(new int[res.size()][]);
}
}
时间复杂度:O(N)
空间复杂度:O(1)
方法一:滑动窗口——Go
func findContinuousSequence(target int)(res [][]int) {
i,j,sum:=1,2,3
for i<=target/2{
if target>sum{
j++
sum+=j
}else{
if target==sum{
tmp:=make([]int,j-i+1)
for k:=i;k<=j;k++{
tmp[k-i]=k
}
res=append(res,tmp)
}
sum-=i
i++
}
}
return
}
时间复杂度:O(N)
空间复杂度:O(1)
方法二:枚举法——Java
枚举每个正整数为起点,判断以它为起点的序列和 sum 是否等于 target 即可,由于题目要求序列长度至少大于 2,所以枚举的上界为(target / 2)向下取整
class Solution {
public int[][] findContinuousSequence(int target) {
List<int[]> vec = new ArrayList<int[]>();
int sum = 0, limit = (target - 1) / 2; // (target - 1) / 2 等效于 target / 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()][]);
}
}