第一章 栈和队列
1.7 生成窗口最大值数组
【题目】
一个整形数组 arr 和 一个大小为 w 的窗口从数组的最左边滑到最右边,窗口每次向右边滑一个位置。如果数组长度为 n,窗口大小为 w,则一共产生 n-w+1 个窗口的最大值。
请实现一个函数:
- 输入:整形数组 arr,窗口大小为 w。
- 输出:一个长度为 n-w+1 的数组 res,res[i] 表示每一个窗口状态下的最大值。
【难度】
尉 ★★☆☆
【题解】
本题最容易想到的是时间复杂度为 O(N×w) 的解法,但是并不符合题意。如果要达到时间复杂度 O(N) ,则需要借助双端队列实现窗口最大值的更新。首先生成双端队列 deque,其中存放数组 arr 中的下标。
- 假设遍历到 arr[i],deque 的入队规则为:
- 如果 deque 为空,直接把下标加入 deque 队尾;
- 如果 deque 不为空,取当前 deque 队尾存放的下标,假设为 j:
- 如果 arr[j] > arr[i],直接把下标 i 加入 deque 的队尾;
- 如果 arr[j] ≤ arr[i],把下标 j 从 deque 队尾弹出。
- 假设遍历到 arr[i],deque 的出队规则为:如果 deque 队头的下标小于等于 i-w,则当前 deque 队头的下标已过期,即当前下标位于窗口外。此时弹出当前队头的下标即可。
- 根据 deque 的入队规则和出队规则,deque 拥有维护窗口大小为 w 的子数组的最大值更新的结构。
上述过程中,每个下标最多进 deque 一次,出 deque 一次,所以在遍历过程中双端队列的操作的时间复杂度为 O(N)。
【实现】
- MaxWindow.java
import java.util.Deque;
import java.util.LinkedList;
public class MaxWindow {
private int[] arr;
private int window;
private int[] res;
public MaxWindow() {
}
public MaxWindow(int[] arr, int window) {