返回

剑指 Offer——I. 滑动窗口的最大值(JavaScript 实现)

前端

剑指 Offer——I. 滑动窗口的最大值

给定一个整数数组和一个窗口大小 k,请找出所有滑动窗口里的最大值。

示例 1:

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]

示例 2:

输入:nums = [1], k = 1
输出:[1]

提示:

  • 1 <= nums.length <= 10^5
  • -10^4 <= nums[i] <= 10^4
  • 1 <= k <= nums.length

解题思路

暴力法

暴力法就是定义一个滑动窗口,然后通过循环不断地去移动这个窗口,直到窗口走到最后,然后分别求出每一个窗口的最大值,存到最终结果数组中,最后返回

虽然通过暴力法也能够通过,但是时间复杂度非常高,达到了 O(nk),其中 n 是数组的长度,k 是窗口的大小。

滑动窗口解法

滑动窗口解法是使用一个双端队列来维护一个大小为 k 的窗口,然后通过不断地将窗口向后移动,来得到窗口中最大的值。

具体步骤如下:

  1. 初始化一个双端队列 deque,将窗口内的元素从小到大依次加入到 deque 中。
  2. 将窗口向后移动一位,并将 deque 中最小的元素弹出。
  3. 将窗口中最大的元素加入到 deque 中。
  4. 重复步骤 2 和步骤 3,直到窗口移动到最后。
  5. 将 deque 中的元素依次取出,即为窗口中的最大值。

JavaScript 实现

/**
 * 求滑动窗口的最大值
 * @param {number[]} nums 数组
 * @param {number} k 滑动窗口大小
 * @return {number[]} 滑动窗口中的最大值
 */
const maxSlidingWindow = (nums, k) => {
  if (nums === null || nums.length === 0 || k <= 0 || k > nums.length) {
    throw new Error("Invalid input!");
  }
  const deque = [];
  const result = [];
  for (let i = 0; i < nums.length; i++) {
    // 将 deque 中比当前元素小的元素弹出
    while (deque.length > 0 && nums[deque[deque.length - 1]] < nums[i]) {
      deque.pop();
    }
    // 将当前元素加入到 deque 中
    deque.push(i);
    // 当窗口向后移动一位时,将 deque 中最小的元素弹出
    if (i >= k - 1) {
      result.push(nums[deque[0]]);
      if (deque[0] === i - k + 1) {
        deque.shift();
      }
    }
  }
  return result;
};

复杂度分析

  • 时间复杂度:O(n),其中 n 是数组的长度。
  • 空间复杂度:O(k),其中 k 是窗口的大小。

结语

滑动窗口是一种重要的算法技术,在很多场景中都有应用。在本文中,我们介绍了滑动窗口的实现原理和应用场景,并通过 JavaScript 实现了一个滑动窗口算法,来求解剑指 Offer——I. 滑动窗口的最大值。如果您对滑动窗口算法感兴趣,可以参考本文来实现自己的滑动窗口算法。