leecode-滑动窗口最大值

题目描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

思路

暴力求解

首先这个问题只是划定一个数组的范围,叫做窗口,然后输出这个窗口的最大值,直接暴力求解的思路比较简单。
即将每次移动后的窗口找出最大值然后输出即可
窗口的大小为k
数组长度为n
那么数组移动次数为n-k
那么时间复杂度为O((n-k+1)k),即O(nk)
会超出时间限制

优先队列优化

对于每次窗口的移动,改变的只有一个元素(或者两个,一进一出),可以利用这个特点进行优化
因为每次找的都是窗口的最大值,那么优先队列(堆实现)就是最合适的数据结构了
优先队列中存入二元组(元素值,元素索引)
结合优先队列的特点,这个算法的时间复杂度为O(nlgn)
代码如下

class Solution {
    public int[] maxSlidingWindow(int[] nums, int k) {
        int n = nums.length;

        //优先队列中的元素是一个二元组
        //(元素值,元素的索引)
        PriorityQueue<int[]> pq = new PriorityQueue<int[]>(new Comparator<int[]>(){
            public int compare(int[] pair1,int[] pair2){
                
                //return pair2[0]-pair1[0];
                //判断元素值是否相同
                //如果不同,返回差值(这里是让pair[2] - pair[1],意为构建一个最大优先队列)
                //如果相同,返回元素索引的差值,即在元素值相同的情况下,将数组后面的元素放在前面
                //这样做的目的是为了减少后面的移除工作
                return pair1[0] != pair2[0] ? pair2[0] - pair1[0] : pair2[1] - pair1[1];
            }
        });
        //添加前k个元素到优先队列中
        for(int i=0;i<k;++i){
            //添加的元素:(元素值,元素索引)
            pq.offer(new int[]{nums[i],i}); //offer() : 添加一个元素到队列中
        }
        int[] ans = new int[n-k+1];
        ans[0] = pq.peek()[0]; //peek() : 返回队头元素,但并不移除队头元素
        for(int i=k;i<n;++i){//向前移动窗口,从数组的第k+1个元素开始
            pq.offer(new int[]{nums[i],i});
            while(pq.peek()[1] <= i-k){//如果队首元素已经出了窗口,就把这些元素永久的移除
            //注意这里只在队首元素做了移除工作,而对于队中其他超出窗口的元素并没有做这样的工作,
            //因为其他元素在队中并不影响结果的输出
                pq.poll();//poll(),返回并移除队首元素
            }
            ans[i-k+1] = pq.peek()[0];
        }
        return ans;
    }
}

记录一下我的一个逻辑漏洞:
本来是想着当将新的元素入队之前,检查一下现在队首元素是不是还是在窗口内,如果不在窗口内就插入这个元素;如果在窗口内就没必要插入这个新元素了(省去了lgn的时间)。
但实际上这是错误的,因为无法保证这个新元素在后面的过程中不会成为队首元素
也就是说现在插入的元素也许在这一轮不是队首元素,但是有可能随着此时的队首元素被舍弃,它在后面某轮中成为队首元素

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值