JS长度最小的子数组

105 阅读2分钟

🐬题目

力扣题目链接(opens new window)

🦈思路

第一个思路还是暴力解决法,两个for循环(后面力扣更新了数据,暴力解法已经超时了),第二个思路是滑动窗口。

所谓滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。

滑动窗口可以用一个for循环解决两个for所要做的事情,我们这时就需要考虑for(let j...)里面的 j 应该是起始位置还是终止位置呢?如果是起始位置的话,那跟两个for有什么区别呢?

所以这里的 j 应该是终止位置,然而滑动窗口的起始位置应该怎么移动呢?

我们拿s=7, 数组是 2,3,1,2,4,3来举例

最后找到 4,3 是最短距离。

看到这里,感觉跟双指针一样!也可以理解为滑动窗口是双指针法的一种。

🐙滑动窗口

/**
 * 查找和大于等于目标值的最小子数组长度
 *
 * @param target 目标值
 * @param nums 整数数组
 * @returns 返回满足条件的最小子数组长度,若不存在则返回0
 */
function minSubArrayLen(target, arr) {
  // 总和
  let sum = 0;
  // 长度的结果(取最大的)
  let result = Infinity;
  // 起始位置i和终止位置j
  let i = 0;
  for (let j = 0; j < arr.length; j++) {
    sum += arr[j];
    // 应该用while循环,用if的话不然比较一次就结束了
    while (sum >= target) {
      // 如果sum大于target的话
      // 1.保存此时的长度(需要作比较)
      let subLen = j - i + 1;
      result = Math.min(result, subLen);
      // 2.重新计算sum=sum-arr[i]
      sum = sum - arr[i];
      // 3.i向右移动
      i++;
    }
  }
  return result === Infinity ? 0 : result;
}

const arr = [2, 3, 1, 2, 4, 3];
const res = minSubArrayLen(7, arr);
console.log(res);

  • 时间复杂度:O(n),其中 n 是数组的长度。指针 start 和 end 最多各移动 n 次。
  • 空间复杂度:O(1)。

🐠总结

在本题中实现滑动窗口,主要确定如下三点:

  • 窗口内是什么?sum≥target的长度最小的 连续 子数组。
  • 如何移动窗口的起始位置?当sum≥target时,就要移动
  • 如何移动窗口的结束位置?for循环遍历的索引

滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)暴力解法降为O(n)。

参考笔记:代码随想录