【每日算法Day 75】滑动窗口的最大值
Wallace Xu 2020-08-14 队列
# LeetCode 239. 滑动窗口最大值 (opens new window)
# 题目描述
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回滑动窗口中的最大值。
输入满足:
1 <= nums.length <= 10^5
-10^4 <= nums[i] <= 10^4
1 <= k <= nums.length
# 示例
输入: 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
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
# 解题思路
如果对于每个窗口都扫描一遍寻找其中的最大值,则时间复杂度为O(n*k)。由于滑动窗口具有先进先出的特性,所以考虑使用队列来在线性时间内得到当前窗口中的最大值,不过要使用的不是普通的单项队列,使用单调队列能够把时间复杂度将为O(n)。
单调队列的 offer 方法依然在队尾添加元素,但是要把前面比新元素小的元素都删掉,这样单调队列从队首向队尾就会保持单调递减,队列头就永远是当前队列中的最大元素。而当要从滑动窗口中删除最左边的元素时,比较该元素和队列头,如果发现该元素是最大元素,则将队列头出队列。
示例:每次队列的头构成了最终的结果。
滑动窗口的位置 最大值 队列(左边为头)
--------------- ----- ----
[1 3 -1] -3 5 3 6 7 3 [3,-1]
1 [3 -1 -3] 5 3 6 7 3 [3,-1,-3] 1出窗口,但和队列头不同,什么都不用做,-3入队列
1 3 [-1 -3 5] 3 6 7 5 [5] 3出窗口、出队列,5入队列
1 3 -1 [-3 5 3] 6 7 5 [5,3] -1出窗口,3入队列
1 3 -1 -3 [5 3 6] 7 6 [6] -3出窗口,6入队列
1 3 -1 -3 5 [3 6 7] 7 [7] 5出窗口,7入队列
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
代码如下,在该方法中,虽然enqueue操作中含有循环,但是其实nums中的每个元素只会入队和出队一次,所以时间复杂度是O(n),空间复杂度不会超过窗口的大小O(k)。
public class No239_SlidingWindowMaximum {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length, index = 0;
int[] result = new int[n - k + 1];
MonotonicQueue<Integer> queue = new MonotonicQueue<>();
for (int i = 0; i < n; i++) {
if (i < k - 1) {
queue.enqueue(nums[i]);
} else {
queue.enqueue(nums[i]);
result[index++] = queue.getMax();
queue.dequeue(nums[i - k + 1]);
}
}
return result;
}
private class MonotonicQueue<v extends Comparable<v>>{
private Deque<v> deque = new LinkedList<>();
public void enqueue(v value) {
while (!deque.isEmpty() && deque.peekLast().compareTo(value) < 0) {
deque.pollLast();
}
deque.offerLast(value);
}
public void dequeue(v value) {
if (value.equals(deque.peekFirst()))
deque.pollFirst();
}
public v getMax() {
return deque.peekFirst();
}
}
}
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
31
32
33
34
35
36
37
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
31
32
33
34
35
36
37