用大顶堆实现滑动窗口最大值查询

滑动窗口的最大值

http://www.nowcoder.com/questionTerminal/1624bc35a45c42c0bc17d17fa0cba788

import java.util.*;
//思路:用一个大顶堆,保存当前滑动窗口中的数据。滑动窗口每次移动一格,就将前面一个数出堆,后面一个数入堆。
public class Solution {
    public PriorityQueue<Integer> maxQueue = new PriorityQueue<Integer>((o1,o2)->o2-o1);//大顶堆
    public ArrayList<Integer> result = new ArrayList<Integer>();//保存结果
    public ArrayList<Integer> maxInWindows(int [] num, int size)
    {
        if(num==null || num.length<=0 || size<=0 || size>num.length){
            return result;
        }
        int count=0;
        for(;count<size;count++){//初始化滑动窗口
            maxQueue.offer(num[count]);
        }
        while(count<num.length){//对每次操作,找到最大值(用优先队列的大顶堆),然后向后滑动(出堆一个,入堆一个)
            result.add(maxQueue.peek());
            maxQueue.remove(num[count-size]);
            maxQueue.add(num[count]);
            count++;
        }
        result.add(maxQueue.peek());//最后一次入堆后没保存结果,这里额外做一次即可

        return result;
    }
}
全部评论
这个问题很大啊,答主使用PriorityQueue,慢慢分析一下。把窗口大小size记为k,实现初始将k个数入堆,时间O(k*log(k)),算常数时间。接着,开始遍历。从最大堆中取最大值为O(1),借助调用remove(E e)方法来移出元素o,PriorityQueue中提供了三种remove方法,第一种为remove(),删除根元素,本质调用poll()方法,O(logk)。第二种提供索引,表示删除什么位置的元素remove(int i),时间O(logk)。答主用了第三种remove(E e),这需要先遍历数组找到删除元素的索引,从而时间复杂度O(k)。之后调用add(E e),本质是调用offer(E e),offer一个新元素,是通过把新元素放在末尾,然后将新元素不断往上与父母做比较得到,时间复杂度O(logk)。综上,时间复杂度为O(klogk + n(1 + k + logk)) = O(nk),空间复杂度为O(1),和直接暴力解法差别不大。
4 回复 分享
发布于 2021-04-04 12:09
堆删除任一一个节点好像是O(n)的,那这个算法的时间复杂度就是O(nk)(k是窗口大小)的吧。还是,挺慢的,,,
2 回复 分享
发布于 2020-03-09 21:34
你这用了堆的效率其实还不如直接暴力,建议认真思考为什么效率会这么低
2 回复 分享
发布于 2020-07-27 11:24
我刚开始也这样想的,但是复杂度太高了。
1 回复 分享
发布于 2020-09-04 16:39
我也是因为运行超时才看的评论
1 回复 分享
发布于 2022-04-14 08:56
maxQueue.remove(num[count-size]);这一句有一个致命的缺陷,按照值删除的话,如果有重复的值,你无法保证删除的num[count-size]这个元素是最左边的那个
2 回复 分享
发布于 2020-07-22 14:54
堆的删除效率很低啊
点赞 回复 分享
发布于 2020-03-02 03:50
这个时间复杂度和空间复杂度太大了。。。。
点赞 回复 分享
发布于 2020-07-23 14:52
这个堆的删除不仅要遍历整个数组O(n)才能找到指定元素(而且这个元素是按值来索引,似乎还是不确定的),而且删了之后要筛选调整O(logn),还是挺慢的。
点赞 回复 分享
发布于 2020-09-16 11:33
我有一个思路,就是每次用后面一个元素代替要出堆的元素,再对此元素分别上移和下移动进行调整,使得保持堆的性质,每个元素的调整是0(logm),寻找要替换的元素是O(m),所以遍历数组,总时间复杂度为O(n*(logm+m))。这样会比先删除,再增加的效率要高,猜测删除也是用堆最后的节点替换删除节点,再调整,再增加新值,时间复杂度为O(2logm)
点赞 回复 分享
发布于 2020-11-05 13:25
可是我就是这样写的超时啊
点赞 回复 分享
发布于 2022-06-09 22:01
堆排序的时间复杂度为n*logn 超时了吧。题目要求时间复杂度是n
点赞 回复 分享
发布于 2022-09-02 19:38 陕西

相关推荐

我是小红是我:学校换成中南
点赞 评论 收藏
分享
冲芭芭拉鸭:你这图还挺新,偷了。
投递美团等公司10个岗位
点赞 评论 收藏
分享
39 2 评论
分享
牛客网
牛客企业服务