• 每日一题


    题目信息

    • 时间: 2019-07-05

    • 题目链接:Leetcode

    • tag: 队列 双端队列 滑动窗口

    • 难易程度:困难

    • 题目描述:

      给定一个数组 nums 和滑动窗口的大小 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
    

    注意

    1. 你可以假设 k 总是有效的,在输入数组不为空的情况下,1 ≤ k ≤ 输入数组的大小。
    

    解题思路

    本题难点

    数组无序,窗口内的最大值。

    具体思路

    双向队列:在头部进行插入、删除操作,也能在尾部进行插入删除操作。

    单调的双向队列:从队列的头部到尾部,所存储的元素是依次递减(或依次递增)的。

    我们维护一个单调的双向队列,窗口在每次滑动的时候,我就从队列头部取当前窗口中的最大值,每次窗口新进来一个元素的时候,我就将它与队列中的元素进行大小比较:

    • 进来的元素 > 队列的尾部元素:那么先将队列尾部的元素弹出,然后把刚刚进来的元素添到队列的尾部;
    • 进来的元素 < 队列的尾部元素:那么把刚刚进来的元素直接添到队列的尾部即可。

    删除元素:当队列的大小超过窗口的大小时,将队列的最大值弹出,窗口进行滑动。

    代码

    class Solution {
        public int[] maxSlidingWindow(int[] nums, int k) {
            if(nums == null || k == 0){
                return new int[0];
            }
            Deque<Integer> deque = new LinkedList<>();
            int[] res = new int[nums.length - k + 1];
            int count = 0;
            for(int i = 0; i < nums.length; i++){
                // 在队列不为空的情况下,如果队列尾部的元素要比当前的元素小,或等于当前的元素
                // 那么为了维持从大到小的原则,我必须让尾部元素弹出
                while(!deque.isEmpty() && nums[deque.peekLast()] <= nums[i]){
                    deque.pollLast();
                }
               // 不走 while 的话,说明我们正常在队列尾部添加元素
                deque.add(i);
              // 如果滑动窗口已经略过了队列中头部的元素,则将头部元素弹出
                if(deque.peekFirst() == (i - k)){
                    deque.pollFirst();
                }
              // 看看窗口有没有形成,只有形成了大小为 k 的窗口,我才能收集窗口内的最大值
                if(i >= k-1){
                    res[count++] = nums[deque.peekFirst()];
                }
            }
            return res;
        }
    }
    

    复杂度分析:

    • 时间复杂度 O(N) : 其中 n 为数组 nums 长度;线性遍历 nums 占用 O(N) ;每个元素最多仅入队和出队一次,因此单调队列 deque 占用 O(2N) 。
    • 空间复杂度 O(k) : 双端队列 deque 中最多同时存储 k个元素(即窗口大小)。

    其他优秀解答

    解题思路

    改善之后的暴力法

    代码

     public int[] maxSlidingWindow(int[] nums, int k) {
            int len = nums.length;
            if (len == 0){
                return new int[0];
            }
            //定义结果数组
            int[] res = new int[len - k + 1];
            //maxInd记录每次最大值的下标,max记录最大值
            int maxInd = -1, max = Integer.MIN_VALUE;
    
            for (int i = 0; i < len - k + 1; i++) {
                //判断最大值下标是否在滑动窗口的范围内
                if (maxInd >= i){
                    //存在就只需要比较最后面的值是否大于上一个窗口最大值
                    if (nums[i + k - 1] > max){
                        max = nums[i + k - 1];
                        //更新最大值下标
                        maxInd = i + k - 1;
                    }
                }
                //如果不在就重新寻找当前窗口最大值
                else {
                    max = nums[i];
                    for (int j = i; j < i + k; j++) {
                        if (max < nums[j]) {
                            max = nums[j];
                            maxInd = j;
                        }
                    }
                }
                res[i] = max;
            }
            return res;
        }
    
  • 相关阅读:
    基于NIO的同步非阻塞编程完整案例,客户端发送请求,服务端获取数据并返回给客户端数据,客户端获取返回数据
    NIO编程中buffer对象的理解以及API的使用
    使用简单工厂模式写一个简单的计算器!!!
    java数字转字符串前面自动补0或者其他数字
    jQuery Validate自定义金钱验证,是否为金额格式,保留两位小数,并支持千分制货币格式
    javade多任务处理之Executors框架(线程池)实现的内置几种方式与两种基本自定义方式
    【转】asp.net mvc webapi+angular.js案例
    【转】MVC5中的区域(Areas)
    【转】在ASP.NET MVC中,使用Bundle来打包压缩js和css
    scroll pagination.js数据重复加载、分页问题
  • 原文地址:https://www.cnblogs.com/ID-Wangqiang/p/13273074.html
Copyright © 2020-2023  润新知