写了一道 滑动窗口最大值

给你一个整数数组 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. 单调 解决了 比较滑动窗口的最大值问题
  2. 将索引存入单调队列 解决了 滑动窗口的 范围序号问题

直接上代码:

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
27
28
29
30
func maxSlidingWindow(nums []int, k int) []int {
var q []int

// 维持 单调队列的 核心函数
push := func(i int) {
for len(q) > 0 && nums[i] > nums[q[len(q)-1]] {
q = q[:len(q)-1]
}
q = append(q, i)
}

// 先将前k个数push进去形成单调函数,这个是准备条件
for i := 0; i < k; i++ {
push(i)
}

res := make([]int, 0, len(nums)-k+1)

res = append(res, nums[q[0]])
for i := k; i < len(nums); i++ {
push(i)
// 判断现在的最大值是否在范围内
for q[0] < i-k+1 {
q = q[1:]
}
res = append(res, nums[q[0]])
}

return res
}

主要关注一下 pushq[0] < i-k+1 这两块内容并结合我的注释即可

思路总结#

这道题两个特点

  1. 范围内
  2. 最大值

首先我们会思考 单调函数 能够很好满足 最大值这个条件,然后再要思考如何保证 范围内 的最大值—-也就是将索引放入单调队列中,太巧妙了