剑指 Offer 57 - II. 和为s的连续正数序列(滑动窗口模块)

142 阅读1分钟

每日刷题第10天 2021.1.5

和为s的连续正数序列

  • 难度:简单
  • 双指针、滑动窗口

题目

  • 输入一个正整数 target ,输出所有和为 target 的连续正整数序列(至少含有两个数)。
  • 序列内的数字由小到大排列,不同序列按照首个数字从小到大排列。

示例

输入: target = 9
输出: [[2,3,4],[4,5]]
输入: target = 15
输出: [[1,2,3,4,5],[4,5,6],[7,8]]

限制

  • 1 <= target <= 10^5

解法

/**
* @param {number} target
* @return {number[][]}
*/
var findContinuousSequence = function(target) {
// 开始指针
let start = 1;
// 结束指针
let end = 1;
// 记录加和结果
let ans = 0;
// 记录结果
let map = new Map();
// 记录长度
let len = 0;
while (end < target) {
  ans += end;
  if (ans >= target) {
    if (ans == target) {
      len = end - start + 1;
      map.set(start, len);
    }
    // 打破循环
    while(ans >= target) {
      ans -= start;
      start++;
      if (ans == target) {
        len = end - start + 1;
        map.set(start, len);
      }
    }
  }
 end++;
}
// 需要返回:一个二维数组
// map的key 就是开始的数字,map的value就是包含开始数字的长度
let lenM = map.size;
let arr = new Array(lenM);
// 存储获取的结果数组
let arr2 = [...map];
// [ [ 2, 3 ], [ 4, 2 ] ]
for (let i = 0; i < lenM; i++) {
  arr[i] = new Array(arr2[i][1]);
  arr[i][0] = arr2[i][0];
  for (let j = 1; j < arr2[i][1]; j++) {
    arr[i][j] = arr[i][0] + j;
  }
}
return arr;
};

优化

var findContinuousSequence = function(target) {
......处理数据
while (end < target) {
  ans += end;
  // 优化后的代码
  while(ans >= target) {
    if (ans == target) {
      len = end - start + 1;
      map.set(start, len);
    }
    ans -= start;
    start++;
  }
  end++;
}
......转换数据
return arr;

附录

  • 出错原因:end++不应该只在ans<target的时候进行++
    • 遗漏掉的情况: 在while循环start进行打破后,也需要end++
    • 因此end++应该写在最后面,不需要任何的判断条件,直接++即可。
// 错误写法:
// 只有ans最终结果,小于target的时候,才end++
else {
  end++;
}
// 正确写法:
end++;