@(labuladong的算法小抄)[单调队列]
leetcode 239. 滑动窗口最大值
题目描述
解题思路
参考:labuladong的算法小抄P271
在一堆数字中,已知最值为A,如果给这堆数添加一个数B,那么比较一下A和B就可以立即算出新的最值;但如果减少一个数,就不能直接得到最值了,因为如果减少的这个数恰好是A,就需要遍历所有数重新找出新的最值。
因此,由于窗口每次前进的时候,要添加一个数同时减少一个数,所以想得到新的最值不容易。
本题采用单调队列的方法解决。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
/* 单调队列,队列中的元素从队头到队尾保持递减 */
MonotonicQueue window = new MonotonicQueue();
int[] res = new int[nums.length - k + 1];
for (int i = 0; i < nums.length; i++) {
/* 先填满窗口的前k-1 */
if (i < k - 1) {
window.push(nums[i]);
} else {
/* 窗口开始滑动 */
/* 移入新元素 */
window.push(nums[i]);
/* 将当前窗口中的最大值记入结果 */
res[i - k + 1] = window.getMax();
/* 移出窗口最前面的元素 */
window.pop(nums[i - k + 1]);
}
}
return res;
}
private class MonotonicQueue {
/* 双向链表,支持头部和尾部增删元素,复杂度为o(1) */
LinkedList<Integer> q = new LinkedList<>();
/* 在队尾将n入队 */
private void push(int n) {
/* 将两个高个儿元素之间的元素全部出队 */
while (!q.isEmpty() && q.getLast() < n) {
q.removeLast();
}
q.addLast(n);
}
/* 返回队列中的最大值 */
private int getMax() {
/* 队列中的元素从队头到队尾保持递减,因此最大值就是队头元素 */
return q.getFirst();
}
/* 在队头删除元素n */
private void pop(int n) {
/* 如果队头元素正好是要删的元素,则删除;否则,说明要删的元素在之前已经被当成矮个儿出队了,不用管 */
if (q.getFirst() == n) {
q.removeFirst();
}
}
}
}