[ 剑指 Offer 59 - I ] 滑动窗口的最大值(一看就懂的详细文字注释) | 刷题打卡

480 阅读2分钟

题目名称:滑动窗口的最大值

题目地址: leetcode-cn.com/problems/hu…

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

示例:

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

  滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

解法

最大值比较

  • 先获取第一个窗口的最大值,后面加入的依次比较,主要比较两种情况:
    • 1、新加入的值是否大于当前区间内最大值? -> 是则重置最大值
    • 2、从队列尾部移出的元素是否为当前区间最大值? -> 是则重新计算最大值
/**
 * @param {number[]} nums
 * @param {number} k
 * @return {number[]}
 */
var maxSlidingWindow = function (nums, k) {
  if (!nums.length) return []
  const res = []
  const stack = []
  let max = null
  // *  找最大值
  function findMax(list) {
    let max = -Infinity
    for (let i = 0; i < list.length; i++) {
      const val = list[i]
      max = val > max ? val : max
    }
    return max
  }
  for (let i = 0; i < k; i++) {
    const val = nums[i]
    stack.push(val)
  }
  max = findMax(stack)
  res.push(max)
  for (let i = k; i < nums.length; i++) {
    const val = nums[i]
    const tail = stack.shift()
    stack.push(val)
    if (val >= max) {
      // 如果新加入的值比当前最大值还要大
      max = val
    } else if (tail === max) {
      // 如果新加入的值没有最大值大并且shift出去的值就是当前最大值
      max = findMax(stack)
    } else {
      // 新加入的值没有当前最大值大,并且shift出去的也不是当前最大值,那就不用动
    }
    res.push(max)
  }
  return res
}

测试用例


// 测试用例
let nums = [1, 3, -1, -3, 5, 3, 6, 7],
  k = 3

console.time("执行用时")
console.log(maxSlidingWindow(nums, k))
console.timeEnd("执行用时")

总结

  • 滑动窗口常见解法有维持双端队列,让最大值一直处于头部,这种方法极其巧妙的同时也让人极其费解
  • 本解法简化双端队列思想,反而关注新加入的值和弹出的值,比较容易理解

说明

  1. 本题解已同步GitHub地址,可以复制代码进行调试。
  2. 总结出了一套亲测有效的前端无痛刷题项目,有助于算法小白平稳入门,详见leetcode-js-roadmap,希望对从零开始刷题的前端小伙伴们带来帮助~

本文正在参与「掘金 2021 春招闯关活动」, 点击查看 活动详情