剑指–滑动窗口的最大值
1,题目:
2,思路:
方法一:双端队列:(其实用到了单调队列)
1,初始化: 双端队列 deque ,结果列表 res ,数组长度 n ;
2,滑动窗口: 左边界范围 i∈[1−k,n+1−k] ,右边界范围 j∈[0,n−1] ;
若 i>0 且 队首元素 deque[0] == 被删除元素 nums[i−1] :则队首元素出队;
删除 deque 内所有<nums[j] 的元素,以保持 deque 递减;
3,将nums[j] 添加至 deque 尾部;
4,若已形成窗口(即 i≥0 ):将窗口最大值(即队首元素deque[0] )添加至列表res 。
5,返回值: 返回结果列表 res 。
方法二:不使用双端队列:
- maxInd记录每次最大值的下标,max记录最大值
- 判断最大值下标是否在滑动窗口的范围内
- 存在就只需要比较最后面的值是否大于上一个窗口最大值
- 更新最大值下标
- 如果不在就重新寻找当前窗口最大值
3,代码:
方法一:双端队列:(其实用到了单调队列)
//双端队列:(其实用到了单调队列)
/*
1,初始化: 双端队列 deque ,结果列表 res ,数组长度 n ;
2,滑动窗口: 左边界范围 i∈[1−k,n+1−k] ,右边界范围 j∈[0,n−1] ;
若 i>0 且 队首元素 deque[0] == 被删除元素 nums[i−1] :则队首元素出队;
删除 deque 内所有<nums[j] 的元素,以保持 deque 递减;
3,将nums[j] 添加至 deque 尾部;
4,若已形成窗口(即 i≥0 ):将窗口最大值(即队首元素deque[0] )添加至列表res 。
5,返回值: 返回结果列表 res 。
*/
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 0 || k == 0)
return new int[0];
Deque<Integer> deque = new LinkedList<>();
int[] res = new int[nums.length - k + 1];
for(int j = 0, i = 1 - k; j < nums.length; i++, j++) {
if(i > 0 && deque.peekFirst() == nums[i - 1])
deque.removeFirst(); // 删除 deque 中对应的 nums[i-1]
while(!deque.isEmpty() && deque.peekLast() < nums[j])
deque.removeLast(); // 保持 deque 递减
deque.addLast(nums[j]);
if(i >= 0)
res[i] = deque.peekFirst(); // 记录窗口最大值
}
return res;
}
}
方法二:不使用双端队列:
class Solution {
public int[] maxSlidingWindow(int[] nums, int k) {
int len = nums.length;
if (len == 0){
return new int[0];
}
//定义结果数组
int[] res = new int[len - k + 1];
//maxInd记录每次最大值的下标,max记录最大值
int maxInd = -1, max = Integer.MIN_VALUE;
for (int i = 0; i < len - k + 1; i++) {
//判断最大值下标是否在滑动窗口的范围内
if (maxInd >= i){
//存在就只需要比较最后面的值是否大于上一个窗口最大值
if (nums[i + k - 1] > max){
max = nums[i + k - 1];
//更新最大值下标
maxInd = i + k - 1;
}
}
//如果不在就重新寻找当前窗口最大值
else {
max = nums[i];
for (int j = i; j < i + k; j++) {
if (max < nums[j]) {
max = nums[j];
maxInd = j;
}
}
}
res[i] = max;
}
return res;
}
}