剑指 offer 41 数据流中的中位数

剑指 offer 41 数据流中的中位数

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

最大堆 & 最小堆

如图所示,如果数据在容器中已经排序,那么中位数可以由 P 1 P_1 P1 P 2 P_2 P2指向的数得到。如果容器中数据的数目是奇数,那么 P 1 P_1 P1 P 2 P_2 P2指向同一个数据。

此时,整个数据容器被分成两部分。位于容器左边部分的数据比右边的数据小。另外, P 1 P_1 P1指向的数据是左边部分最大的数, P 2 P_2 P2指向的数据是右边部分最小的数。如果能保证数据容器左边的数据小于右边的数据,那么即使左、右两边内部的数据没有排序,也可以根据左边最大的数及右边最小的数得到中位数。用最大堆迅速找出最大数,快速从最小堆中找出最小的数。

解决问题的思路:用一个最大堆实现左边的数据容器,用一个最小堆实现右边的数据容器。往堆中插入一个数据的时间效率是 O ( l o g n ) O(logn) O(logn),只需要 O ( 1 ) O(1) O(1)时间就可以得到位于堆顶的数据。

接下来考虑用最大堆和最小堆实现的一些细节。首先要保证数据平均分配到两个堆中,两个堆中数据的数目只差不能超过1.为了实现平均分配,可以在数据的总数目是偶数的时候向最小堆插入数据,否则插入最大堆。

还要保证最大堆中的所有数据都要小于最小堆中的数据。当数据大的总数目是偶数时,按照前面的分配规则会把新的数据插入最小堆,如果此时这个数据比最大堆中的一些数据要小(小于最大堆中的最大值)。可以先把这个新的数据插入最大堆,接着把最大堆中的最大的数字拿出来插入最小堆。由于最终插入最小堆的数字是原最大堆的最大的数字,这样就保证了最小堆中所有数字都大于最大堆中的数字。

当需要把一个数据插入最大堆,但这个数据大于于最小堆里的一些数据时,这个情形和前面类似。
在这里插入图片描述

class MedianFinder {
    PriorityQueue<Integer> max_que ;
    PriorityQueue<Integer> min_que ;


    /** initialize your data structure here. */
    public MedianFinder() {
        max_que=new PriorityQueue<>(new Comparator<Integer> (){
        public int compare(Integer num1,Integer num2){
            return num2-num1;
        }
    });
        min_que = new PriorityQueue<>(new Comparator<Integer>(){
        public int compare(Integer num1,Integer num2){
            return num1-num2;
        }
    });

    }
    
    public void addNum(int num) {
        if((max_que.size()+min_que.size())%2==0){
            //插入最小堆
            //num要大于最大堆中最大的
            if(max_que.isEmpty()){
                min_que.add(num);
            }
            else if(num>=max_que.peek()){
                min_que.add(num);
            }else{
                min_que.add(max_que.poll());
                max_que.add(num);
                
            }
            
        }else{
            if(num<min_que.peek()){
                max_que.add(num);
            }else{
                max_que.add(min_que.poll());
                min_que.add(num);
            }
            
        }

    }
    
    public double findMedian() {
        if((max_que.size()+min_que.size())%2==0){
            return (max_que.peek()+min_que.peek())/2.0;
        }else{
            return min_que.peek();
        }

    }
}

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

在这里插入图片描述
添加元素的时间复杂度 O ( l o g n ) O(logn) O(logn)
查找中位数的时间复杂度 O ( 1 ) O(1) O(1)
空间复杂度 O ( n ) O(n) O(n),其中 n n n是数据流中元素的数量,最小堆和最大堆最多同时保存 n n n个元素。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值