题目描述
给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
样例描述
思路
单调队列(用双端队列实现) O(nlogk)
核心思路:维护存储下标的单调队列,用下标范围来模拟滑动窗口
- 本题双端队列是左边头,右边尾,整体向右边移动。队列中存储的不是元素,而是下标,为了便于方便判断队首的元素是否还在窗口内。
- 对于每个右端点下标,判断其左端点是否还在窗口内,同时对于尾部新来的元素,判断是否大于队尾的元素,如果大于就不断删除队尾元素。(保证队列中是单调递减的性质,队首是最大值)。
- 可以预先设置结果数组,由于k个一组有个最大值,所以所有窗口最大值的个数为n - k + 1。
- 由右端点向前索引左端点。
代码
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
Deque<Integer> dq = new LinkedList<>();
int res[] = new int[n - k + 1];
int cnt = 0;
//枚举右端点,看左端点是否在窗口内
for (int i = 0; i < n; i ++ ) {
//队列不为空,并且左端点已经超过了队首,说明队首不在窗口内了,弹出队首
if (!dq.isEmpty() && i - k + 1 > dq.peekFirst()) dq.removeFirst();
//队列不为空,新来的元素大于队尾元素,删除所有小于队尾的,因为它们存在没意义
while (!dq.isEmpty() && nums[i] > nums[dq.peekLast()]) dq.removeLast();
//加入新来元素的下标
dq.addLast(i);
//如果长度大于k,才开始求max
if (i >= k - 1) {
res[cnt ++] = nums[dq.peekFirst()];
}
}
return res;
}
}