数据流的中位数

25 篇文章 0 订阅
1 篇文章 0 订阅

在这里插入图片描述

方法一:
双堆法(最大堆+最小堆)
当前两个堆中数据个数为偶数时:

  • 如果新插入数据小于或等于大堆的堆顶,则说明新数据应该插入大堆;此时我们先将大堆堆顶插入小堆中,然后再将新数据插入大堆。
  • **否则**直接将新数据插入小堆。

总而言之,为偶数时必须将小堆增加一个数,具体如何加取决于以上逻辑;

当前两个堆中数据个数为奇数时,有类似的处理方法;

以上操作确保两个堆的数据个数相差不超过1,以便于我们能够一O(1)时间复杂度取得中位数;

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
    auto sz=maxh.size()+minh.size();
    if(sz%2==0)
    {
        if(!maxh.empty()&&num<=maxh.top())
        {
            minh.push(maxh.top());
            maxh.pop();
            maxh.push(num);
        }
        else minh.push(num);
    }
        
     else
    {
        if(!minh.empty()&&num>=minh.top())
        {
            maxh.push(minh.top());
            minh.pop();
            minh.push(num);
        }
         else maxh.push(num);        
    }
    }
    
    double findMedian() {
       auto sz=minh.size()+maxh.size();
        if(sz%2==0)return (maxh.top()+minh.top())/2.0;
        else return minh.top();
    }
    private:
    priority_queue<int,vector<int>,less<int>>maxh;
    priority_queue<int,vector<int>,greater<int>>minh;
};

双堆法不管是插入还是查找时间复杂度都是O(lgn),应该算是最优解法了;

还有一些其他方法:
方法二:
如数组+二分法,插入复杂度O(n),查找的复杂度O(1);

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
      auto ret=lower_bound(data.begin(),data.end(),num);
      data.insert(ret,num);
    }
    
    double findMedian() {
        auto sz=data.size();
        if(sz%2==0)return (data[sz/2]+data[sz/2-1])/2.0;
        return data[sz/2];
    }
    
    vector<int>data;
};

方法三:
利用红黑树,插入的时间复杂度O(lgn),数据保持有序状态,但是唯一的问题是如何找到中位数。因此,引入两个指针,分别指向中间的两个数,如果总个数为数,两个指针指向同一个元素;否则,指向两个连续的数。

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
     if(data.empty())
     {
         data.insert(num);
         lmed=data.begin();
         rmed=lmed;
         return;
     }
       auto sz=data.size(); 
        if(sz&1)
        {
            data.insert(num);
            if(num<*lmed)
            {
                --lmed;
            }
            else
                ++rmed;
        }
        
        else
        {
            auto ret=data.insert(num);
            if(num>=*lmed&&num<*rmed)
            {
                lmed=ret;
                rmed=ret;
            }
            else if(num<*lmed)
            {
                --rmed;
            }
            else
                ++lmed;
        }
        
    }
    
    double findMedian() {
      if(data.size()&1)
          return *lmed;
        else
            return (*lmed+*rmed)/2.0;
    }
    private:
    multiset<int> data;
    multiset<int>::iterator lmed;
    multiset<int>::iterator rmed;
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值