• Leetcode239.滑动窗口


    239. 滑动窗口最大值

    Difficulty: 困难

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

    返回滑动窗口中的最大值。

    示例 1:

    输入: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:

    输入:nums = [1], k = 1
    输出:[1]
    

    示例 3:

    输入:nums = [1,-1], k = 1
    输出:[1,-1]
    

    示例 4:

    输入:nums = [9,11], k = 2
    输出:[11]
    

    示例 5:

    输入:nums = [4,-2], k = 2
    输出:[4]
    

    提示:

    • 1 <= nums.length <= 10<sup>5</sup>
    • -10<sup>4</sup> <= nums[i] <= 10<sup>4</sup>
    • 1 <= k <= nums.length

    题意

    在一个滑动窗口内,每次滑动位置时给出当前窗口的最大值。这题和剑指Offer上的59题是一样的。

    思路

    使用双端队列。维护一个队列,队列中的元素是窗口中的值,且保证队列是降序排列的。当窗口右移一个位置时,先判断左移出的数值是否是双端队列的队头(队列中的最大值),如果是,说明当前窗口中的最大值移出去了,需要更新最大值,因为队列的降序的,此时新的队头就是最大值;判断完左移出的值后,判断右移进窗口的值,当新的值比队尾来得小,那么就出队,反之,将新的值入队(这样保证队列始终是降序的,出队的值是小于新值的,同时在数组中他们比新值考前,当新值没有出队时,他们不可能是最大值)。

    使用优先队列。使用双端队列时,可以看到时间复杂度位O(nk),当数据量大时,效率还是很低的。从官方题解中启发,只要维护一个含有窗口中的最大值的数据结构就行--优先队列。所以,每次我们要拿取最大值时,先判断大顶堆的头部是不是在窗口内就行。

    代码:

    /**
    *使用双端队列
    */
    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            int[] res = new int[nums.length - k + 1];
            LinkedList<Integer> queue = new LinkedList<>();
            for(int i=0, idx=0; i<nums.length; i++){
                if(i - k >= 0 && i - k == queue.peekFirst()){
                    queue.pollFirst();
                }
                while(!queue.isEmpty() && nums[i] > nums[queue.peekLast()])
                    queue.pollLast();
                queue.offerLast(i);
                res[idx] = nums[queue.peekFirst()];
                idx = i - k + 1 < 0 ? 0 : idx + 1;
            }
            return res;
        }
    }
    

    执行用时:33 ms, 在所有 Java 提交中击败了66.81%的用户
    内存消耗:50.2 MB, 在所有 Java 提交中击败了70.71%的用户

    /**
    *使用优先级队列
    */
    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            int[] res = new int[nums.length - k+1];
            PriorityQueue<Node> queue = new PriorityQueue<>((a, b) -> b.val-a.val);
            for(int i=0, idx = 0; i<nums.length; i++){
                queue.offer(new Node(nums[i], i));
                while(i-k >= 0 && queue.peek().idx <i-k+1)
                    queue.poll();
                res[idx] = queue.peek().val;
                idx = i-k+1 >= 0 ? idx + 1 : 0;
            }
            return res;
        }
    
        class Node{
            int val;
            int idx;
            public Node(int val, int idx){
                this.val = val;
                this.idx = idx;
            }
        }
    }
    

    执行用时:76 ms, 在所有 Java 提交中击败了11.36%的用户
    内存消耗:59.2 MB, 在所有 Java 提交中击败了8.85%的用户

  • 相关阅读:
    手机震动的节奏 Vibrator
    Andorid ZoomControls的用法
    Android AutoCompleteTextView用法
    动态添加/删除Spinner 菜单
    [国家集训队]排队
    [HNOI2012]永无乡
    文艺平衡树
    【AGC板刷记录】
    高级打字机
    [JSC2021 A~D + F]
  • 原文地址:https://www.cnblogs.com/liuyongyu/p/14223730.html
Copyright © 2020-2023  润新知