LC 239 滑动窗口最大值:从暴力超时到单调队列一遍过

刷滑动窗口的题,你是不是上手就想写两层循环?我当初也是这么干的,结果这道 hard 题一提交直接超时,给我整懵了。今天就聊聊怎么用「单调队列」把这道题轻松拿捏。

题目说个明白

题目其实不复杂。给你一个整数数组,一个大小为 k 的窗口从左往右慢慢滑,每次挪一格。你要返回每个窗口里的最大值,拼成一个新数组。

我踩过的第一个坑:暴力法

最开始我思路特别直白。窗口滑到哪,我就遍历哪 k 个数字找最大值。写起来两分钟,跑示例也没问题,一提交就超时。毕竟 O (n*k) 的时间复杂度,数组一长根本顶不住。

后来我慢慢反应过来。每次窗口只移动一格,只走一个旧元素、来一个新元素。为了找最大值重新扫一遍窗口,也太浪费了。有没有什么结构,能直接告诉我当前窗口最大值是谁?这时候就轮到单调队列出场了。

单调队列到底是啥

我们要维护的是一个单调递减的队列。重点是,队列里存的不是数值,是元素的下标。

这么做有两个好处:队头永远是当前窗口最大值的下标,拿结果直接用。也方便判断队头元素有没有滑出窗口的左边界。

具体怎么操作

遍历数组的时候,每来一个新元素,先做第一件事。把队列尾部所有对应值比当前元素小的下标,全弹出去。你想啊,这些数既比新来的小,还比它先离开窗口,以后不可能再当最大值了,留着纯纯占位置。弹完就把当前下标加到队尾。

接着做第二件事,检查队头。窗口左边界是 i - k + 1,如果队头下标小于左边界,说明它已经滑出去了,直接从队头删掉。

最后,当窗口正式形成的时候(也就是 i >= k-1),把队头对应的值丢进结果数组就 ok。

拿示例里的 [1,3,-1,-3,5,3,6,7],k=3 走两步你就懂了。

  • i=0,队列为空,加 0,队列:[0]
  • i=1,3 比 1 大,弹出 0,加 1,队列:[1]
  • i=2,-1 比 3 小,加 2,队列:[1,2]这时候窗口刚好形成,队头是 1,对应值 3,放进结果。后面的步骤都是一个逻辑,顺下来就行。

代码实现

直接上 JavaScript 代码,注释我都标好了,都是我当初踩过的坑。

javascript 复制代码
var maxSlidingWindow = function(nums, k) {
    const res = [];
    const deque = []; // 单调递减队列,存元素下标
    const n = nums.length;

    for (let i = 0; i < n; i++) {
        // 队尾元素比当前小就弹出,维持递减
        // 别漏了等于的情况,不然重复元素会出问题
        while (deque.length && nums[i] >= nums[deque.at(-1)]) {
            deque.pop();
        }
        deque.push(i);

        const left = i - k + 1; // 窗口左边界
        // 队头已经滑出窗口,从队头移除
        if (deque[0] < left) {
            deque.shift();
        }

        // 窗口形成后,收集当前最大值
        if (left >= 0) {
            res.push(nums[deque[0]]);
        }
    }
    return res;
};

这里我必须提一句,队列一定要存下标。我一开始图省事存数值,结果边界处理全乱套,卡了半小时才反应过来。

复杂度咋样

时间复杂度 O (n),每个元素最多进队一次、出队一次,效率拉满。空间复杂度 O (k),队列最多装 k 个元素。

最后唠两句

这道题本质上考的就是滑动窗口 + 单调队列的组合。核心是理解 "为什么要维护单调递减"------ 把不可能成为最大值的元素提前淘汰掉。我踩过的坑还挺多,存值不存下标、漏了等于的情况、忘了检查队头出界...... 说多了都是泪。

你第一次做这题是直接想到单调队列,还是跟我一样先写了暴力?有没有在什么奇怪的地方踩过坑?评论区唠唠,我每条都会看。觉得文章有用的话,点个赞让更多小伙伴看到呀~

相关推荐
辰烨chenye10 小时前
LeetCode Hot 100 题解 · 普通数组篇
算法·leetcode·职场和发展
passerby606113 小时前
如何自己造一个时间处理库
前端·javascript·github
hqyjzsb13 小时前
零 AI 项目经验,学 Python 转型 AI 的正确顺序是什么?
开发语言·人工智能·python·算法·职场和发展·数据挖掘·数据分析
辰烨chenye13 小时前
LeetCode Hot 100 题解 · 二分篇
java·算法·leetcode
微功夫信息技术13 小时前
分层多智能体强化学习驱动的非急救转运公平 - 效率统一调度系统研究与实践
人工智能·学习·算法·动态规划
小羊没烦恼!14 小时前
Hello Web API系列教程——Web API与国际化
java·服务器·前端·javascript·php
sanjiaomao33314 小时前
从论文公式到Python实现:用单元测试校验滑动平均算法
python·算法·单元测试
乐迪信息14 小时前
如何通过AI防爆摄像机精准判断船舶超速?
大数据·人工智能·算法·安全·目标跟踪
大圣编蚕15 小时前
Java ByteArrayInputStream 详解:从入门到实战
java·开发语言·算法
mayaairi16 小时前
Vue2 组件通讯(三):全局事件总线、PubSub、插槽与组件实例属性
前端·javascript·vue.js