数据流中的中位数

剑指OFFER题40------按牛客网通过率排序

时间:2019.1.4.2206
作者:Waitt

题目

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

时间限制:1秒 空间限制:32768K 热度指数:99031

解法

解法1

利vector保存数值,每次插入数值之后重新对向量进行排序,取出中间的数据

解法2

利用平衡二叉树保存数据,但是一般AVL树并无标准库实现,自己写插入和删除操作比较繁琐。

解法3

利用一个大顶堆和一个小顶堆存放数据,大顶堆的数据均比小顶堆小。大顶堆的容量<=小顶堆容量+1。
数据数目为奇数时,返回大顶堆的堆顶;
数据数目为偶数时,返回(大顶堆堆顶+小顶堆堆顶)/2.0;由于返回时数据类型可能为double,所以此处应除2.0

利用优先队列实现大顶堆和小顶堆:priority_queue

class Solution {
public:
    priority_queue<int, vector<int> > a;//大顶堆
    priority_queue<int, vector<int>, greater<int> > b;//小顶堆
    int c=0;//计数
    void Insert(int num)
    {
        c++;
        a.push(num);//每次都先存入大顶堆中
        if(c%2==0)//当为偶数时,将大顶堆的堆顶存入小顶堆
        {
            b.push(a.top());
            a.pop();
        }
        if(c>2)//由于每次都是存入大顶堆,故总数为奇数时,需要查验大顶堆的堆顶是否比小顶堆的堆顶小
        {
            if(c%2!=0)//当为奇数时,进行查验,确保小顶堆的所有数据都比大顶堆的大
            {
                if(a.top()>b.top())
                //当大顶堆的堆顶大于小顶堆的堆顶时,进行数据替换。确保小顶堆的所有数据都比大顶堆的大
                {
                    b.push(a.top());
                    a.pop();
                    a.push(b.top());
                    b.pop();
                }
            }
        }
    }

    double GetMedian()
    { 
        if(c%2==0)
            return (a.top()+b.top())/2.0;//为了确保返回的为double,此处应除以2.0
        else
            return a.top();
    }

};

利用make_heap创建堆进行实现
由于此题是一个一个输入数据,因此无需用make_heap,用push_heap即可

class Solution {
public:
    vector<int> a,b;//大顶堆a,小顶堆b
    void Insert(int num)
    {
        if(a.empty()||num<a[0])//小数放入小顶堆
        {
            a.push_back(num);
            //由于此题是一个一个输入数据,因此无需用make_heap,用push_heap即可
            push_heap(a.begin(),a.end());
        }
        else//大数放入大顶堆
        {
            b.push_back(num);
            push_heap(b.begin(),b.end(),greater<>());
        }
        if(a.size()>(b.size()+1))//数组容量判断
        {
            b.push_back(a[0]);
            push_heap(b.begin(),b.end(),greater<>());
            pop_heap(a.begin(),a.end());
            a.pop_back();
        }
        if(b.size()>a.size())//数组容量判断
        {
            a.push_back(b[0]);
            push_heap(a.begin(),a.end());
            pop_heap(b.begin(),b.end(),greater<>());
            b.pop_back();
        }
    }
    double GetMedian()
    { 
        if(a.size()>b.size())//说明此时为奇数个数
            return a[0];
        return (a[0]+b[0])/2.0;
    }

};

TIPS

优先队列的本质是用堆实现的,其拥有队列的所有属性。
其默认顺序与堆一样:less<>为大顶堆。当需要小顶堆时:greater<>.
优先队列priority_queue:https://blog.csdn.net/AAMahone/article/details/82787184
优先队列priority_queue:https://blog.csdn.net/weixin_36888577/article/details/79937886

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值