【LeetCode-0239】滑动窗口最大值-单列队列,难度:困难

88 阅读1分钟

原题

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。 你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。

解法

单列队列

单列队列解决:保证单列队列递减性质

  • 通过保存索引来维持最大值在队首
    1. 遍历,初始化窗口
    2. 第一个窗口最大值,存入ans[0]
    3. 遍历,比前者大的就替换,前者(队尾)出队,后者(新元素)入队
    4. 判断窗体移动,判断队首索引是否在窗体内,不在就删除
    5. i+1-k下标存储第i+1个窗体最大值
public int[] maxSlidindWindow(int[] nums,int k){
        Deque<Integer> deque = new LinkedList<>();
        int n = nums.length;
        for (int i =0;i<k;++i){//第一组窗口形成
            while(!deque.isEmpty()&&nums[i]>nums[deque.peekLast()]){//比前者大的就替换,前者(队尾)出队,后者入队
                deque.pollLast();//比如是11 12,那么11出队
            }
            deque.offerLast(i);
        }

        int[] ans = new int[n-k+1];//结果数组
        ans[0] = nums[deque.peekFirst()];//第一个永远最大
        for(int i=k;i<n;++i){
            while(!deque.isEmpty()&&nums[i]>nums[deque.peekLast()]){//比前者大的就替换,前者(队尾)出队,后者入队
                deque.pollLast();//比如是11 12,那么11出队
            }
            deque.offerLast(i);
            //重点!下面判断窗体移动,判断队首索引是否在窗体内,不在就删除
            //i+1-k代表新窗体实际范围之外的位置,deque.peekFirst()+1表示队首索引在实际位置
            while (deque.peekFirst()<=i-k){//deque.peekFirst()+1 <= i+1-k
                deque.pollFirst();
            }
            //i-k+1即第几个窗体
            ans[i-k+1] = nums[deque.peekFirst()];
        }
        return  ans;
    }