滑动窗口

124 阅读3分钟

滑动窗口算法在JavaScript中实现查找队列中的最大值,通常涉及到一个特定大小的窗口在数组上滑动,并且每次滑动时计算当前窗口内的最大值。这种问题可以通过维护一个双端队列(deque)来高效地解决,其中队列中的元素按照它们在原数组中的顺序存储索引,并且保持队列内的元素对应的值是非递增的(即从队首到队尾,元素对应的值逐渐减小)。这样做的好处是,队首总是当前窗口的最大值。

下面我们将详细介绍如何使用JavaScript实现这一算法:

初始化

首先,我们需要定义几个变量:

  • queue:一个用来保存数组索引的双端队列。
  • result:用于保存每个滑动窗口的最大值结果。
  • nums:输入的数组。
  • k:滑动窗口的大小。
function maxSlidingWindow(nums, k) {
  let queue = []; // 存储索引
  let result = [];

遍历数组

接下来,我们开始遍历数组nums,对于每一个元素:

  1. 移除不在窗口范围内的元素:如果queue的第一个元素(队首)已经不在当前窗口范围内(即i - queue[0] >= k),则将其从队首移除。
  2. 维持非递增顺序:当新元素大于等于队列尾部元素时,将队列尾部的所有小于新元素的值都移除,以确保队列中的元素值是非递增的。
  3. 添加当前元素的索引到队列:将当前元素的索引加入队列尾部。
  4. 记录最大值:当窗口形成后(即i + 1 >= k),将队首元素对应的值(即当前窗口的最大值)加入结果数组result中。
  for (let i = 0; i < nums.length; i++) {
    if (queue.length > 0 && i - queue[0] >= k) {
      queue.shift(); // 移除队首元素 
    }
    
    while (queue.length > 0 && nums[queue[queue.length - 1]] < nums[i]) {
      queue.pop(); // 移除所有小于当前元素的值 
    }
    
    queue.push(i); // 添加当前元素的索引
    
    if (i + 1 >= k) {
      result.push(nums[queue[0]]); // 记录当前窗口的最大值 
    }
  }

返回结果

最后,返回结果数组result,它包含了每个滑动窗口的最大值。

  return result;
}

完整代码示例

以下是完整的JavaScript函数实现,用于求解滑动窗口的最大值:

function maxSlidingWindow(nums, k) {
  let queue = []; // 存储索引
  let result = [];

  for (let i = 0; i < nums.length; i++) {
    if (queue.length > 0 && i - queue[0] >= k) {
      queue.shift();
    }
    
    while (queue.length > 0 && nums[queue[queue.length - 1]] < nums[i]) {
      queue.pop();
    }
    
    queue.push(i);
    
    if (i + 1 >= k) {
      result.push(nums[queue[0]]);
    }
  }

  return result;
}

// 示例用法
console.log(maxSlidingWindow([1,3,-1,-3,5,3,6,7], 3)); // 输出: [3,3,5,5,6,7]

这个解决方案的时间复杂度为O(n),因为每个元素最多只会被插入和删除一次。空间复杂度为O(k),因为队列中最多只会有k个元素。

通过上述方法,我们可以有效地利用滑动窗口技巧,在线性时间内找到所有滑动窗口的最大值。这种方法不仅适用于寻找最大值的问题,也可以通过调整逻辑来适应寻找最小值等类似的问题。此外,这种方法可以很容易地扩展到其他类型的数据结构或更复杂的查询条件。