牛客网:数据流中的中位数

 

这题可以用三种方法去做

目录

1.暴力

2.插入排序

3.堆


1.暴力

对所有的数据直接读入之后用sort排序输出中位数即可。

这里类型转换用了C++11的static_cast<>

由于是一次快排,所以是时间复杂度是O(nlogn)

代码如下所示:

class Solution {
public:
    #define SCD static_cast<double>
    vector<int> v;
    void Insert(int num) {
        v.push_back(num);
    }

    double GetMedian() { 
        sort(v.begin(), v.end());
        int sz=v.size();
        if(sz & 1){//奇数则返回中间那位数
            return SCD(v[sz>>1]);
        }else{
            return SCD(v[sz>>1]+v[(sz>>1)-1])/2;
        }
    }

};

2.插入排序

这里用到了一个lower_bound接口:

其作用是返回数组中第一个大于或等于被查数的值

求中位数的做法和之前没啥不一样的。

这里的时间复杂度对每一个数都是O(logn)的,总的时间复杂度是O(nlogn)

class Solution {
public:
    #define SCD static_cast<double>
    vector<int> v;
    void Insert(int num) {
        if(v.empty()){
            v.push_back(num);
        }else{
            auto it=lower_bound(v.begin(), v.end(), num);
            v.insert(it, num);
        }
    }

    double GetMedian() { 
        int sz=v.size();
        if(sz&1){
            return SCD(v[sz>>1]);
        }else{
            return SCD(v[sz>>1]+v[(sz>>1)-1])/2;
        }
    }

};

3.堆

这里学习一下大小顶堆的直接写法:

小顶堆:

priority(int, vector<int>, less<int>)

大顶堆:

priority(int, vector<int>, greater<int>)

我们的任务是维护两个大小顶堆,可以这么理解,我们只需要用两个数把小的和大的两个部分隔开不就好了么,为什么一定要求两个部分有序呢?基于这种考虑,我们采用堆排序。

注意一些细节,小的那一部分存在大顶堆中,大的那一部分存在小顶堆中。

思路如下:

既然是要求中位数,我们希望两个堆的元素数目尽量接近,分为以下几种情况:

1.大顶堆的元素数目多于小顶堆的元素数目,如果这时候我们要把新的数据放进来,显然我们应该放到小顶堆,但是放的是我们当前新加的元素吗?显然不是,我们这个时候要利用大顶堆,先把当前元素放入大顶堆,然后将新生成的堆顶取出放入小顶堆中。

2.其余情况其实差不多,等于其实是随便放到哪个堆的。

这个时候求中位数就根据两个堆的元素数目进行求取就行了

代码如下所示:

class Solution {
public:
    #define SCD static_cast<double>
    priority_queue<int> min_q;//小顶堆
    priority_queue<int, vector<int>, greater<int>> max_q;//大顶堆
    void Insert(int num) {
        if(max_q.size()>=min_q.size()){
            max_q.push(num);
            min_q.push(max_q.top());
            max_q.pop();
        }else{
            min_q.push(num);
            max_q.push(min_q.top());
            min_q.pop();
        }
    }

    double GetMedian() { 
        if(max_q.size()==min_q.size()){
            return SCD(max_q.top()+min_q.top())/2;
        }else if(max_q.size()>min_q.size()){
            return SCD(max_q.top());
        }else{
            return SCD(min_q.top());
        }
    }

};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值