首页 重启DAY17 单调队列 滑动窗口最大值
文章
取消

重启DAY17 单调队列 滑动窗口最大值

跟着灵茶山艾府大佬学习算法思路的day17(并没有在一个月内掌握hot100)

b站链接如下:

单调队列 滑动窗口最大值【基础算法精讲 27】

滑动窗口最大值 题目描述:

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回 滑动窗口中的最大值

示例 1:

1
2
3
4
5
6
7
8
9
10
11
输入: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

示例 2:

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

提示:

  • 1 <= nums.length <= 105
  • -104 <= nums[i] <= 104
  • 1 <= k <= nums.length

思路:

很明显能想到暴力的时间复杂度是o(n*2)。优化方法可以这么考虑:想象一下自己在飞机上,自机窗往下看,看到了一座座由数组元素组成的山,数字就是山的高度,随着飞机从左往右飞,视野内的最高山峰是会发生变化的。

在看到4之后,先于4出现的2和1永远不能成为视野里最高的山了。紧接下来又看到一个2,这个2虽然小于4,但有可能是后续的最大值,于是先将2记录下来。当3出现时,2永远不可能成为最大值了,那么就可以去掉2记录3。

在记录最后一个数时,4已经不在视野中,所以可以先把4去掉,再记录2。

我们每次遇到一个数,都会把前面比它小的数去掉,遇到相同数字时也可以去掉,保留最右的数即可。最后我们记录的数从左到右是严格递减的,又因为我们需要在队头和队尾同时操作,所以是单调队列。

image-20260602041357527

判断一道题用单调栈还是单调队列,看有没有窗口:

特征用哪个
固定大小的滑动窗口 + 求窗口内最值单调队列
找某个方向最近的大/小元素单调栈

有窗口用队列,没窗口用栈。单调队列需求的是过期清理,窗口滑动后,队首就需要被删除。如果没有窗口,就没有过期元素,此时队列和栈没有区别,用栈会更简单。

以维护单调性的角度而言,单调栈和单调队列是一致的,单调栈通过弹出栈顶维护单调性,单调队列也通过弹出队尾维护单调性,不过除此之外,单调队列也要通过删除队首维护窗口大小。

image-20260602043305295

代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
var maxSlidingWindow = function(nums, k) {
    const ans = [];
    const q = new Deque(); // datastructures-js/deque

    for (let i = 0; i < nums.length; i++) {
        // 1. 右边入
        while (!q.isEmpty() && nums[q.back()] <= nums[i]) {
            q.popBack(); // 维护 q 的单调性
        }
        q.pushBack(i); // 注意保存的是下标,这样下面可以判断队首是否离开窗口

        // 2. 左边出
        const left = i - k + 1; // 窗口左端点
        if (q.front() < left) { // 每次循环时都保证队首离开窗口
            q.popFront();
        }

        // 3. 在窗口左端点处记录答案
        if (left >= 0) {
            // 由于队首到队尾单调递减,所以窗口最大值就在队首
            ans.push(nums[q.front()]);
        }
    }

    return ans;
};

总结:

复杂度分析类似单调栈,每个元素出入队至多一次。时间复杂度为o(n),空间复杂度为o(min(k, U))。

image-20260602184943858

本文由作者按照 CC BY 4.0 进行授权

重启DAY17 单调栈

hot100 图论