leetcode 295 find median from data stream 找到数据流中的中位数

思路:

维护一个大根堆和一个小根堆,大根堆中放的是小数,小根堆中放的是大树,这样中位数就在大根堆和小根堆中堆顶中间作用

怎么理解呢,试想最简单的查找方法是什么,是排序,然后找到中位数,复杂度是O(N^2)

我们现在想象一下,中位数不就是排序后前一半数和后一半数中间的数吗。那我们现在不排序,使用堆,代码中用优先级队列表示。我们大根堆放小数,大根堆堆顶就是小数中最大的数;小根堆放大树,小根堆堆顶是大数中最小的数。那么中位数不就是两个堆顶中间产生吗,要么是前面那个数(大根堆堆顶,当然前提是均衡),要么是平均数(大根堆小根堆堆顶平均数)

下面java代码

class MedianFinder {
    PriorityQueue <Integer> minHeap;
    PriorityQueue <Integer> maxHeap;
    /** initialize your data structure here. */
    public MedianFinder() {
        this.minHeap= new PriorityQueue <>();
        this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() {
            public int compare(Integer o1,Integer o2){
                return o2-o1;
            }
        });
    }
    
    public void addNum(int num) {
        //小根堆中的堆顶大于大根堆中的数
        if(num<findMedian()){
            //当前加入的数比中位数小,应该放前面那个大根堆中去
            maxHeap.add(num);
        }
        else{
            minHeap.add(num);
        }
        //设置是不允许大堆数目比小堆数目多
        if(maxHeap.size()>minHeap.size()){
            minHeap.add(maxHeap.poll());
        }
        //设置允许小堆数目比大堆数目最多多1个结点
        if(minHeap.size()-maxHeap.size()>1){
            maxHeap.add(minHeap.poll());
        }
    }
    
    public double findMedian() {
        if(maxHeap.isEmpty()&&minHeap.isEmpty())
           return 0;
        if(maxHeap.size()==minHeap.size())
           return 1.0*(maxHeap.peek()+minHeap.peek())/2.0;
        else
           return minHeap.peek();//这一个就是说我始终在小根堆里面多放一个数,如果个数为奇数
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

注意,兄弟们

代码中findMedian()后面的return 为什么是返回小根堆堆顶呢???

因为设置的是在addNum中,就是要小堆始终比大堆最多多放一个,而大堆数目不允许比小堆中数多。这样有什么用呢,就是说,中位数要么是平均数(俩堆数目相等),要么是小堆中堆顶(奇数个数,小堆多放一个,你说中位数在哪里)

那有人问了,我可不可以让大堆多放一个?那是显而易见的可以啊

下面贴出代码

class MedianFinder {
    PriorityQueue <Integer> minHeap;
    PriorityQueue <Integer> maxHeap;
    /** initialize your data structure here. */
    public MedianFinder() {
        this.minHeap= new PriorityQueue <>();
        this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() {
            public int compare(Integer o1,Integer o2){
                return o2-o1;
            }
        });
    }
    
    public void addNum(int num) {
        //小根堆中的堆顶大于大根堆中的数
        if(num<findMedian()){
            //当前加入的数比中位数小,应该放前面那个大根堆中去
            maxHeap.add(num);
        }
        else{
            minHeap.add(num);
        }
        //设置是不允许大堆数目比小堆数目多
        if(maxHeap.size()-minHeap.size()>1){
            minHeap.add(maxHeap.poll());
        }
        //设置允许小堆数目比大堆数目最多多1个结点
        if(minHeap.size()-maxHeap.size()>0){
            maxHeap.add(minHeap.poll());
        }
    }
    
    public double findMedian() {
        if(maxHeap.isEmpty()&&minHeap.isEmpty())
           return 0;
        if(maxHeap.size()==minHeap.size())
           return 1.0*(maxHeap.peek()+minHeap.peek())/2.0;
        else
           return maxHeap.peek();//这一个就是说我始终在小根堆里面多放一个数,如果个数为奇数
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

注意到了吗,我只改了参数罢了,其他都没动

猜你喜欢

转载自blog.csdn.net/yysave/article/details/83960122
今日推荐