题目
给定一个数组 nums 和滑动窗口的大小 k,请找出所有滑动窗口里的最大值。
解题思路
这题比较复杂,首先最简单的就是暴力破解,每次对窗口中的数组求最大值, 但是这样效率太低了,所以这里我们使用了单调队列去做这题,首先这个队列是单调递减的,这样每次取队列的第一个值就可以放到结果数组中,然后我们首先要初始这个单调队列, 就是循环K次,将数据按照单调递减去放,首先每次循环我们要确保队列中有一个数, 这里还有个问题, 我们其实是需要有个顺序情况的, 即如何确保数据。 首先单调递减,确保了大小, 然后往后添加变相确定了顺序, 但是这里是窗口函数,所以这里还需要删除头结点, 如果移动的数据是在队列的头部, 其实是需要删除, 这样后面那个数据就自动移到了头部, 然后我们详细可以列出一下情况:1.给的数据大于了这个单调队列的最大值, 那么我们只需要最大值就可以, 所以等于将队列清空后放入该数 2.给的数符合队列的单调递减,即最后一个值大于给的数, 那么我们将这个数直接添加到这个队列中 3.给的数在队列中间, 那么我们就循环将大于给定数的末尾数字都删除掉,然后将该数加入到这个单调队列中, 这里其实窗口函数很简单, 看代码注释就知道了, 可以得到窗口的初始index和结尾index,并且只需要遍历一次目标数组即可,具体代码实现如下。
Java代码实现
import java.util.Deque;
import java.util.LinkedList;
public class MaxSlidingWindow {
public int[] maxSlidingWindow(int[] nums, int k) {
int n = nums.length;
if (n*k == 0){
return new int[0];
}
int[] res = new int[n - k + 1];
int resIndex = 0;
Deque<Integer> deque = new LinkedList<>();
//初始化窗口
for (int i = 0; i < k; i++) {
// 删除队列中所有小于当前元素的元素,保证队列中的元素是递减的
while (!deque.isEmpty() && nums[i] >= deque.peekLast()) {
deque.pollLast();
}
deque.addLast(nums[i]); // 将当前元素加入队列中
}
res[resIndex++] = deque.peekFirst();
//继续按照窗口滑动, 这里i就是endIndex, i-k就是startIndex, 滑动范围
for (int i = k; i < nums.length; i++) {
if(nums[i -k] == deque.peekFirst()){
deque.pollFirst();
}
while (!deque.isEmpty() && nums[i] > deque.peekLast()) {
deque.pollLast();
}
deque.addLast(nums[i]); // 将当前元素加入队列中
res[resIndex++] = deque.peekFirst();
}
return res;
}
}