239. 最大スライディングウィンドウ
問題解決のアイデア
- 各スライディング ウィンドウの最大値を計算する鍵は、単調キューを使用してウィンドウを実装することです。
- 単調なキューの場合は、末尾に要素を追加し、先頭から要素を削除します。
- 要素の追加操作: 末尾からループし、現在の要素より小さい要素を削除します。
- 最大値要素の取得と先頭要素の直接取得
- 要素の削除操作は、head 要素を直接削除します。
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();
}
}
}
}