跳到正文
第 239 题困难

滑动窗口最大值

Sliding Window Maximum

给定数组和窗口大小 k,窗口从左向右滑动,返回每个窗口中的最大值。

在力扣中练习

题目描述

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

返回 滑动窗口中的最大值 。

 

示例 1:

输入: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:

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

 

提示:

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

解题思路

主解法

单调队列 · 存下标

队首永远是当前窗口最大值,队尾维护递减

每个窗口都重新找最大值是 O(nk)。观察窗口滑动时只有两个变化:右边进一个数,左边可能出一个数。

用一个双端队列存下标:

  • 新元素入队前,从队尾弹掉所有不大于它的元素——它们不可能再成为最大值;
  • 下标超出窗口左边界时,从队首弹出;
  • 队首就是当前窗口最大值。

自拟主例 [4,2,7,3,5,1],k=3:7 到来时把 4、2 都从队尾挤掉;最后一个 1 入队后,7 的下标过期,队首变成 5。

分步图解

i = 0,nums[0] = 4;入队。

i
0
deque
0
nums
0
1
2
3
4
5
4
2
7
3
5
1
i
窗口宽度 3
result
[ ]
deque(存下标)
队首
0值 4
队首是当前窗口最大值
1 / 3
4、2 依次入队;7 到来时把 4 和 2 都从队尾挤掉,队首直接变成 7。

每个下标最多入队一次、出队一次,时间 O(n),空间 O(k)。

分步图解

i = 3,nums[3] = 3;入队。窗口最大值 7。

i
3
deque
2,3
nums
0
1
2
3
4
5
4
2
7
3
5
1
i
窗口宽度 3
result
77
deque(存下标)
队首
2值 7
3值 3
队首是当前窗口最大值
1 / 4
3、5 入队,5 挤掉 3;最后一个 1 入队后队首 7 过期,窗口最大值变成 5。
时间 O(n)空间 O(k)

易错点

  • 队列存值而不是下标:无法判断队首是否已经滑出窗口。
  • 先取结果再清理过期队首:可能把已经离开窗口的最大值写进答案。
  • 用 < 而不是 <= 弹队尾:相等元素会残留在队列里,窗口变长后可能误判。
  • 只在 i == k-1 时取结果:之后每个窗口都要记录。
对照解法

大顶堆 · 延迟删除

堆顶是最大值,过期就弹掉

时间 O(n log n),比单调队列慢;但实现简单,适合面试先写出可运行版本,再优化到 O(n)。

把窗口内的元素放进大顶堆,堆顶就是最大值。窗口右移时,旧元素不会立刻删除,而是等到它浮到堆顶、且下标已经过期时再弹出。

每个元素入堆一次、出堆至多一次,时间 O(n log n),空间 O(n)。它不如单调队列快,但“延迟删除”的思路很通用,适合处理滑动窗口 + 最值。

  1. 1i 从 0 到 n-1:把 (nums[i], i) 入堆。
  2. 2窗口形成后,若堆顶下标 <= i-k,弹出。
  3. 3记录堆顶的值。
时间 O(n log n)空间 O(n)

易错点

  • 堆里只存值:无法判断堆顶是否过期。
  • 窗口还没形成就开始记录:i < k-1 时堆里元素不足 k 个。

代码与演示

主解法配有图解;对照解法用于比较思路、复杂度或实现方式。

演示输入nums = [4,2,7,3,5,1], k = 3

deque 存下标,值从队首到队尾递减;先处理前几个元素。

k
3
nums
0
1
2
3
4
5
4
2
7
3
5
1
窗口宽度 3
result
[ ]
deque(存下标)
队首
空
队首是当前窗口最大值
1 / 8
查看 C++ 代码

延伸阅读

  • 单调队列适合“窗口内的最值”;如果要求窗口内第 k 大,需要换成两个堆或有序结构。
  • 队列里存下标而不是值,是所有滑动窗口过期判断的共同要求。