239. 최대 슬라이딩 윈도우
문제 해결 아이디어
- 각 슬라이딩 윈도우의 최대값을 계산하는 핵심은 단조로운 큐를 사용하여 윈도우를 구현하는 것입니다.
- 단조로운 대기열의 경우 꼬리에 요소를 추가하고 머리에서 요소를 삭제합니다.
- 요소 추가 작업: 끝부터 반복하고 현재 요소보다 작은 요소를 삭제합니다.
- 최대값 요소를 가져오고 헤드 요소를 직접 가져옵니다.
- 요소 삭제 작업은 헤드 요소를 직접 삭제합니다.
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
// 借助单调队列 计算每一个滑动窗口的最大值
MonotonicQueue window = new MonotonicQueue();// 单调队列窗口
List<Integer> res = new ArrayList<>();
for(int i = 0; i < nums.length; i++){
if(i < k - 1){
window.push(nums[i]);// 先把前面k- 1 个元素填满
}else{
// 窗口开始向前面移动
// 移入新的元素
window.push(nums[i]);
// 因为是单调队列 直接计算最大值
res.add(window.max());
// 移除最后的元素
window.pop(nums[i - k + 1]);
}
}
// 将List 类型转换为int[] 数组 作为返回值
int[] arr = new int[res.size()];
for(int i = 0; i < res.size(); i++){
arr[i] = res.get(i);
}
return arr;
}
// 单调队列的实现 尾部添加元素 头部删除元素 那么头部元素是最大值
// 维护的单调队列 是需要从尾部到头部的元素 全部单调递增
class MonotonicQueue{
// 使用双链表 模拟队列 支持头部和尾部添加和删除元素
private LinkedList<Integer> maxq = new LinkedList<>();
public void push(int n){
// 尾部添加一个元素 需要维护单调队列 从尾部到头部 单调递增的性质
// 从尾部开始 将前面小于她的元素 全部删除掉 这样维护的就是一个单调队列
while(!maxq.isEmpty() && maxq.getLast() < n){
maxq.pollLast();// 删除尾部元素
}
maxq.addLast(n);// 添加元素 尾部添加元素
}
// 计算最大元素 直接就是取出 头部元素 因为头部元素最大
public int max(){
return maxq.getFirst();
}
// 头部删除元素
public void pop(int n){
if(n == maxq.getFirst()){
maxq.pollFirst();
}
}
}
}