Skip to content

Latest commit

 

History

History
73 lines (62 loc) · 3.65 KB

README.md

File metadata and controls

73 lines (62 loc) · 3.65 KB

239.滑动窗口最大值

问题描述

给定一个数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口 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

解决方案

  这题是剑指的一道题,因为滑动窗口的长度是固定的,即当滑动窗口开始移动时,左边的元素出队,右边的元素入队(先进先出),换一个思路就是相当于是求一个队列中的最大值。和leetcode-155的最小栈类似,我们搞了一个辅助栈用来存放历史的最大值,那么这题我们可以采用一个类似的想法,用一个辅助队列来存放历史的最大值。
  那么什么样的值可能成为窗口的最大值呢。和剑指一样,我们用一组数据来模拟辅助队列的情况。

滑动窗口的位置              辅助队列        解释
[1],3,-1,-3,6,3,5,7        1              队列空此时1为窗口最大值
[1,3],-1,-3,6,3,5,7        3              3>1,1不可能成为窗口的最大值了
[1,3,-1],-3,6,3,5,7        3,-1           -1<3,如果3滑出窗口,-1有可能成为窗口最大值
1,[3,-1,-3],6,3,5,7        3,-1,-3        -3<-1,如果3,-1滑出窗口,-3有可能成为窗口最大值
1,3,[-1,-3,6],3,5,7        6              3滑出窗口,辅助队列变成[-1,-3];又6>-1,-1-3都不可能成为窗口最大值
1,3,-1,[-3,6,3],5,7        6,3            3<6,如果6滑出窗口,3有可能成为窗口最大值
1,3,-1,-3,[6,3,5],7        6,5            5>3,即使6滑出窗口,3也不可能成为窗口最大值
1,3,-1,-3,6,[3,5,7]        7              6滑出窗口,辅助队列变成[5];又7>5,5不可能成为窗口最大值了

  这样一来思路就很明确了,相当于每次我们都要清除辅助队列中比当前值小的元素:

  • 如果当前窗口的右端的值大于辅助队列的队头,清空队列(队头元素应该是辅助队列的最大值);
  • 如果队尾小于当前窗口右端,队尾就出队,直到找到比当前值大的队尾;

  另外,因为要考虑到队列中的值滑出窗口的情况,所以辅助队列中存放的是窗口元素的地址,这样当窗口左指针大于辅助队列中存放值的时候,辅助队列中的元素就出列。

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];
        int l=0,r=0;
        while (l<=nums.length-k && r<nums.length){
            //去除已经滑出窗口的最大值
            while (!deque.isEmpty() && deque.peekFirst()<l) deque.pollFirst();
            //如果当前值大于队头,清空队列
            while (!deque.isEmpty() && nums[deque.peekFirst()]<nums[r]) deque.pollFirst();
            //如果当前值大于队尾值,队尾出队
            while (!deque.isEmpty() && nums[deque.peekLast()]<nums[r]) deque.pollLast();
            //当前值进队
            deque.addLast(r);
            if (r-l+1==k) {
                res[index++]=nums[deque.peekFirst()];
                l++;
            }
            r++;
        }
        return res;
    }
}