别让队列“堵车”!初学者的滑动窗口最大值通关秘籍

121 阅读4分钟

你有没有遇到过这样的场景:一群小伙伴排队买奶茶,每次只能有k个人进店,老板想知道每一批进店小伙伴中,谁的身高最高?这其实就是著名的“滑动窗口最大值”问题!别眨眼,今天带你用最通俗的语言,玩转队列和滑动窗口,顺便避开那些让人头秃的坑!


一、滑动窗口是什么?队列又是啥?

先来点“人话”解释:

  • 滑动窗口:就像你用尺子在一串数字上滑动,每次只看尺子覆盖的那一段,尺子长度就是窗口大小k。
  • 队列:现实生活中排队买奶茶,先来先服务,谁先进谁先出(FIFO)。

在算法世界里,这俩是黄金搭档,尤其是在处理“连续区间最大值”这类问题时,简直是如鱼得水。


二、LeetCode 239:滑动窗口最大值

题目大意:给你一个数组和一个窗口大小k,让你输出每个窗口里的最大值。

举个栗子:

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

每次窗口滑动一格,记录当前窗口的最大值。


三、初学者的“暴力解法”——简单粗暴但慢

很多同学第一反应就是:每次窗口滑动时,把窗口里的数都遍历一遍,找最大值。

代码长这样:

function getMax(arr){
    let max = -Infinity;
    for (let i = 0; i < arr.length; i++) {
        if (arr[i] > max) max = arr[i];
    }
    return max;
}

主函数里,每次窗口滑动都调用一次 getMax,结果就是——能跑,但大数据下会超时


四、暴力解法的“致命伤”

  • 时间复杂度高:每次窗口都要遍历k个元素,总共n-k+1个窗口,复杂度O(nk)。
  • 大数据下会超时:LeetCode会毫不留情地给你一个“超时警告”。
  • 代码虽然简单,但效率感人

五、初学者常见的“引用大坑”

有同学会这样初始化二维数组:

const arr2 = new Array(5).fill(new Array(5).fill(0));

看起来很美好,实际上每一行都是同一个数组的引用,改一个全都变!
正确姿势

const arr2 = new Array(5).fill().map(() => new Array(5).fill(0));

每一行都是独立的,互不干扰。


六、队列的正确打开方式

队列在滑动窗口问题中,常用来维护窗口内的元素。最常见的就是单调队列,它能让你在O(1)时间内拿到窗口最大值。

单调队列的核心思想

  • 队列里只存可能成为最大值的元素(或索引)。
  • 新元素进队时,把队尾比它小的都踢出去。
  • 队首永远是当前窗口的最大值。

七、单调队列解法——高效又优雅

来一段“掘金级”代码:

var maxSlidingWindow = function(nums, k) {
    const deque = [];
    const res = [];
    for (let i = 0; i < nums.length; i++) {
        // 队尾小于当前元素的都出队
        while (deque.length && nums[i] >= nums[deque[deque.length - 1]]) {
            deque.pop();
        }
        deque.push(i);
        // 队首超出窗口范围就出队
        if (deque[0] <= i - k) {
            deque.shift();
        }
        // 记录最大值
        if (i >= k - 1) {
            res.push(nums[deque[0]]);
        }
    }
    return res;
};

时间复杂度O(n),LeetCode大数据也能轻松通过!


八、幽默小结:队列的“买奶茶哲学”

想象一下,队列里每个人都想当“窗口最大值”,但只要有比你高的进来,你就得乖乖让位。队首的那位,永远是当前窗口的“身高王者”。
这就是单调队列的精髓:只留最有竞争力的选手,其他的都请出队!


九、初学者常见问题答疑

  1. 为什么不用数组的sort?
    • sort复杂度O(nlogn),而且会改变原数组,得不偿失。
  2. 为什么不用暴力法?
    • 小数据可以,大数据就“超时”了。
  3. 单调队列难吗?
    • 其实就是维护一个“只存最大值候选人”的队列,理解了就很简单。

十、写在最后

滑动窗口和队列是算法面试中的高频考点。初学时别怕踩坑,理解原理、勤加练习,队列和窗口就会变成你算法路上的好帮手。
下次再遇到“窗口最大值”,你就能自信地说:“这题我会!”