随时找到数据流的中位数

设计一个MedianHolder结构,能够在线性时间内添加整数,并在常数时间内获取所有已添加整数的中位数。使用大根堆和小根堆实现,大根堆存储较小的一半数,小根堆存储较大的一半数,确保堆的平衡以维持中位数的快速获取。
摘要由CSDN通过智能技术生成

题目描述

有一个源源不断的吐出整数的数据流,假设你有足够的空间来保存吐出的数。请设计一个名叫MedianHolder的结构,MedianHolder可以随时取得之前吐出所有数的中位数。
[要求]
1. 如果MedianHolder已经保存了吐出的N个数,那么将一个新数加入到MedianHolder的过程,其时间复杂度是O(logN)。

2. 取得已经吐出的N个数整体的中位数的过程,时间复杂度为O(1)

 

每行有一个整数opt表示操作类型

若opt=1,则接下来有一个整数N表示将N加入到结构中。
若opt=2,则表示询问当前所有数的中位数
 

示例1

输入

[[1,5],[2],[1,3],[2],[1,6],[2],[1,7],[2]]

返回值

[5,4,5,5.5]

说明

第一次查询时结构内的数为:5
第二次查询时结构内的数为:3 5
第二次查询时结构内的数为:3 5 6
第二次查询时结构内的数为:3 5 6 7
 

示例2

输入

[[2],[1,1],[2]]

返回值

[-1,1]

【解析】

    设计MedianHolder中两个堆,一个大根堆,一个小根堆。其中大根堆中接收所有数中较小的一半,这个堆中的堆顶就是较小那部分数中的最大值。小根堆则接收所有数中较大的一半,对顶则是较大一半数中的最小值。

    具体流程如下:

     1)第一个出现的数直接插入大根堆

     2)以后每出现一个数num,判断num是否小于或者等于大根堆的堆顶。如果是,num进入大根堆;如果不是,num进入小根堆

     3)每一个数加入完成后,判断大根堆和小根堆的大小。如果两个堆得个数相差超过1,从较多的那个堆中弹出堆顶,加入另一个堆。

class Solution {
public:
    /**
     * the medians
     * @param operations int整型vector<vector<>> ops
     * @return double浮点型vector
     */
    vector<double> flowmedian(vector<vector<int> >& operations) {
        // write code here
        vector<double> res;
        for(int i=0;i<operations.size();++i){
            if(operations[i][0]==1){
                insertNum(operations[i][1]);
            }else{
                res.push_back(getMedian());
            }
        }
        return res;
    }
    void insertNum(int num){
        int size = min_heap.size() + max_heap.size();
        if(size%2==0){
            if(max_heap.size()==0){
                max_heap.push(num);
                return;
            }
            if(num>min_heap.top()){
                max_heap.push(min_heap.top());
                min_heap.pop();
                min_heap.push(num);
            }else{
                max_heap.push(num);
            }
        }else{
            if(num<max_heap.top()){
                min_heap.push(max_heap.top());
                max_heap.pop();
                max_heap.push(num);
            }else{
                min_heap.push(num);
            }
        }
    }
    double getMedian(){
        int size = min_heap.size() + max_heap.size();
        if(size ==0) return -1;
        if(size%2 == 0)
            return (max_heap.top() + min_heap.top())*0.5;
        else
            return max_heap.top();
    }
private:
    priority_queue<int, vector<int>, greater<int>> min_heap;//最小堆
    priority_queue<int, vector<int>, less<int>> max_heap;//最大堆
};
class MedianFinder {
public:
    /** initialize your data structure here. */
    priority_queue<int, vector<int>, greater<int>> Small;//小根堆
    priority_queue<int, vector<int>, less<int>> Big;//大根堆

    MedianFinder() {

    }
    
    void addNum(int num) {
        //保证大顶堆的数据都小于小顶堆
		//优先存入大根堆
        if(Small.size()==Big.size()){
            Small.emplace(num);
            Big.emplace(Small.top());
            Small.pop();
        }else{
            Big.emplace(num);
            Small.emplace(Big.top());
            Big.pop();
        }
    }
    
    double findMedian() {
        return Small.size()!=Big.size()?Big.top():(Small.top()+Big.top())/2.0;
    }
};

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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值