本文最后更新于:2025-01-22T10:04:00+08:00
给你一个整数数组 nums
,有一个大小为 k
的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k
个数字。滑动窗口每次只向右移动一位。
返回 滑动窗口中的最大值 。
示例 1:
1 2 3 4 5 6 7 8 9 10 11 输入: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
示例 2:
提示:
1 <= nums.length <= 105
-104 <= nums[i] <= 104
1 <= k <= nums.length
题解思路 单调递减队列 这道题需要使用一种叫做单调递减队列 的数据结构,这个队列的队列头始终是队列最大值,然后从头到尾数值依次变小 ,向该队列中添加元素时需要进行特殊处理 ,比如向队列中添加num,需要判断队列尾部的值是否大于num,如果小于,此时直接入队则会破坏队列单调递减的特性,则需要将队尾元素出队,然后继续判断,直到找到队列中比num值大的数或者队列为null,然后将num入队
图解单调递减队列
使用单调递减队列,在滑动窗口时,将窗口内的值加入单调递减队列,如果单调队列的最大值「头节点」被移出滑动窗口,则移出头元素,代码如下i >= k && nums[i - k] == queue.peek()
,其中nums[ i - k ]
就是刚刚移出窗口的值,如果这个值大于了队列中的最大值,则说明这个最大值已经出了滑动窗口范围,需要从队列中移除queue.poll()
;
输入: nums = [1,3,-1,-3,5,3,6,7], 和 k = 3,动画如下:
当i >= k - 1
时,每次将队列中的最大值加入结果集合,why?因为一开始指针i是从0开始的,此时窗口还没有真正展开,此时队列中的最大值也不作数,因为你不确定后面窗口内会不会还有更大的值。简单来说,就是需要等窗口真正打开时,窗口内的最大值才能算数,比如现在 k ==3,即窗口大小为3,那么需要指针 i 指向 2 时窗口大小才真正成为3,此时才需要记录第一个最大值。
题解代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 static class MonotonicStack { private final LinkedList<Integer> deque = new LinkedList <>(); public Integer peek () { return deque.peekFirst(); } public void poll () { deque.pollFirst(); } public void offer (Integer m) { while (!deque.isEmpty() && deque.peekLast() < m) { deque.pollLast(); } deque.offerLast(m); } }public int [] maxSlidingWindow(int [] nums, int k) { MonotonicStack queue = new MonotonicStack (); List<Integer> list = new ArrayList <>(); for (int i = 0 ; i < nums.length; i++) { int num = nums[i]; queue.offer(num); if (i >= k && nums[i - k] == queue.peek()) { queue.poll(); } if (i >= k - 1 ) { list.add(queue.peek()); } } return list.stream() .mapToInt(Integer::intValue) .toArray(); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 static class Solution { static class MyQueue { Deque<Integer> deque = new LinkedList <>(); void poll (int val) { if (!deque.isEmpty() && val == deque.peek()) { deque.poll(); } } void add (int val) { while (!deque.isEmpty() && val > deque.getLast()) { deque.removeLast(); } deque.add(val); } int peek () { return deque.peek(); } } public int [] maxSlidingWindow(int [] nums, int k) { if (nums.length == 1 ) { return nums; } int [] res = new int [nums.length - k + 1 ]; int resIdx = 0 ; MyQueue myQueue = new MyQueue (); for (int i = 0 ; i < k; i++) { myQueue.add(nums[i]); } res[resIdx++] = myQueue.peek(); for (int i = k; i < nums.length; i++) { myQueue.poll(nums[i - k]); myQueue.add(nums[i]); res[resIdx++] = myQueue.peek(); } return res; } }