https://leetcode-cn.com/problems/hua-dong-chuang-kou-de-zui-da-zhi-lcof/
题目描述
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
输入输出样例
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3
输出: [3,3,5,5,6,7]
解释:
滑动窗口的位置 最大值
--------------- -----
[1 3 -1] -3 5 3 6 7 3
1 [3 -1 -3] 5 3 6 7 3
1 3 [-1 -3 5] 3 6 7 5
1 3 -1 [-3 5 3] 6 7 5
1 3 -1 -3 [5 3 6] 7 6
1 3 -1 -3 5 [3 6 7] 7
题解
这道题的难点是如何动态维护一个 k个元素窗口的最大值。
由于需要从窗口头部删除元素和从尾部添加元素,因此考虑到使用双端队列。
比较重要的一个思考点: 一旦出现一个比之前元素大的数字,那么小的那个数字就会被去除,因为它不可能成为当前窗口的最大值了。
class Solution {
// 细节很多
public int[] maxSlidingWindow(int[] nums, int k) {
if(nums.length == 0 || k == 0) return new int[0];
// int r = 0, l = 1 - k;
int[] res = new int[nums.length - k + 1];
int index = 0;
// 使用双端队列
Deque<Integer> deque = new LinkedList<Integer>();
for(int r=0, l=1-k; r<nums.length; l++,r++){
// 将窗口左边的元素删除
if(l > 0 && deque.peekFirst() == nums[l-1]) deque.removeFirst();
// 维持双端队列是递减的
while(!deque.isEmpty() && deque.peekLast() < nums[r]) deque.removeLast();
// 添加进队列
deque.addLast(nums[r]);
// 如果满足k窗口大小了
if(l >= 0){
res[index++] = 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;
}
}