题目链接:https://leetcode.cn/problems/sliding-window-maximum/description/?envType=study-plan-v2&envId=top-100-liked
优先队列
大根堆存储每个窗口最大值,如果最大值不在窗口内,则弹出
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
//创建一个优先队列,大根堆,堆顶是队列最大值,比较函数第二个参数大
PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>() {
public int compare(int[] pair1, int[] pair2){
return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
}
});
//队列存储首个窗口的数组元素和下标
for(int i = 0; i < k; i++){
pq.offer(new int[]{nums[i], i});
}
//存储答案
int[] ans = new int[n - k + 1];
//存储第一个窗口最大值
ans[0] = pq.peek()[0];
//遍历剩下的窗口
for(int i = k; i < n; i++){
//每次存储当前位置元素和下标
pq.offer(new int[]{nums[i], i});
//如果最大值不在窗口内,则弹出,可能有多个都不在窗口内
while(pq.peek()[1] <= i - k){
pq.poll();
}
//更新答案
ans[i - k + 1] = pq.peek()[0];
}
return ans;
}
}
单调队列
维护一个单调递减的双端队列,如果都在窗口内,且左边小于右边,那么左边的值不可能为最大值,直接弹出,如果队首出窗口了,还需要弹出,所以需要个双端队列
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
//定义一个双端队列,存储数组下标,队列从大到小排列
Deque<Integer> deque = new LinkedList<Integer>();
//存储第一个窗口
for(int i = 0; i < k; i++){
//如果当前元素大于队尾,则把队尾去掉
while(!deque.isEmpty() && nums[i] > nums[deque.peekLast()]){
deque.pollLast();
}
//从队尾插入
deque.offerLast(i);
}
//存储答案
int[] ans = new int[n - k + 1];
//存储第一个窗口最大值
ans[0] = nums[deque.peekFirst()];
//遍历剩下的窗口
for(int i = k; i < n; i++){
while(!deque.isEmpty() && nums[i] > nums[deque.peekLast()]){
deque.pollLast();
}
deque.offerLast(i);
//当队首不在窗口内,则弹出
while(deque.peekFirst() <= i - k){
deque.pollFirst();
}
//更新答案
ans[i - k + 1] = nums[deque.peekFirst()];
}
return ans;
}
}