题目
给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。
返回滑动窗口中的最大值。
思路
暴力:遍历一遍的过程中每次从窗口找到最大的数组,O(n * k)
需要一个队列,在这个队列中放进窗口里的元素,然后随着窗口的移动,队列也一进一出,每次移动后,队列告诉我们里面的最大值是什么。
单调队列,即单调递减或单调递增的队列
保存队列中的元素单调递增或者单调递减,需要自己去实现这个单调队列。
java中使用 Deque deque = new LinkedList<>(); 实现队列
使用Deque自定义一个单调队列插入,弹出,获取一个元素。
- 将前k个元素放入单调队列中,取出第一个最大元素
- 遍历接下来的数组元素,尝试将窗口中即将被移除的元素从单调队列弹出
- 尝试将进入窗口中的元素加入到单调队列
- 取出单调队列的最大值,即第一个元素,保存到数组中
始终维护了一个单调的队列,从而每次很容易得取出当前窗口中得最大值。
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
int j = 0;
//存放结果
int[] res = new int[n - k + 1];
CustomQueue queue = new CustomQueue();
//先将数组前k的元素放入自定义单调队列中
for(int i = 0 ; i < k ; i++){
queue.add(nums[i]);
}
res[j++] = queue.getMaxValue();
//遍历数组 i始终是位于滑动窗口最右边
for(int i = k ; i < n ; i++){
//1.滑动窗口中被移除的元素在单调队列尝试弹出
queue.poll(nums[i-k]);
//2.滑动窗口中新加入的元素在单调队列中尝试加入
queue.add(nums[i]);
//3.记录当前滑动窗口最大值
res[j++] = queue.getMaxValue();
}
return res;
}
}
//自定义单调队列
class CustomQueue{
Deque<Integer> deque = new LinkedList<>();
//弹出元素,如果出口元素和滑动窗口的值一样则弹出
public void poll(int val){
if(!deque.isEmpty() && val == deque.peekFirst()){
deque.pollFirst();
}
}
//放入元素.如果入口元素的值小于滑动窗口的值,则弹出入口元素,直到满足为止
public void add(int val){
while(!deque.isEmpty() && deque.peekLast() < val){
deque.pollLast();
}
deque.addLast(val);
}
//获取单调队列中最大值
public int getMaxValue(){
return deque.peekFirst();
}
}