Leetcode刷题笔记——剑指 Offer 41. 数据流中的中位数【优先队列】

题目

在这里插入图片描述

思路

本题难点就是需要对自定义的数据结构每加一个元素,就排序放入数据结构中,并且还需要高效地访问数据结构中的中间元素(特定顺序元素,而非顺序访问)
对于自动排序,C++中的优先队列可以实现

优先队列具有队列的所有特性,包括基本操作,只是在这基础上添加了内部的一个排序,它本质是一个堆实现的
其基本操作如下:

priority_queue <int,vector<int>,greater<int> > pq_greater;//大顶堆,里面的元素从大到小排序
priority_queue <int,vector<int>,less<int> >pq_less;//小顶堆,里面的元素从小到大排序

top 访问队头元素
empty 队列是否为空
size 返回队列内元素个数
push 插入元素到队尾 (并排序)
emplace 原地构造一个元素并插入队列
pop 弹出队头元素
swap 交换内容

需要高效访问中间的元素,需要两个优先队列(两个堆),大顶堆用于保存这些元素中小的一半,小顶堆用于保存元素中大的一半,这样的话,大顶堆的堆头是较小的一半元素的最大值,小顶堆的堆头是较大的一半元素的最小值,通过这两个值就可以得到中位数。

为了实现上述保存逻辑,在添加元素时,可以首先将该往大顶堆中添加,随后返回大顶堆的堆头,这个堆头就是当前大顶堆中的最大元素,再将其push到小顶堆(目的是添加新元素后,重新分配元素保持较大元素在小顶堆)。完成这系列操作后,判断大小堆的size,我们只允许它们的size相等或者小顶堆比大顶堆大一个size(谁比谁大都无所谓),如果小顶堆的size超出了限制,则将小顶堆中的最小元素取出放入大顶堆(目的是使较小元素放在大顶堆)

每次添加元素时就维护这两个堆,那么取中位数就很方便了。

代码

class MedianFinder {
private:
    priority_queue<int, vector<int>, less<int>> pq_less;
    priority_queue<int, vector<int>, greater<int>> pq_great;
public:
    /** initialize your data structure here. */
    MedianFinder() {
        while(!pq_less.empty()){
            pq_less.pop();
        }
        while(!pq_great.empty()){
            pq_great.pop();
        }
    }
    
    void addNum(int num) {
        pq_great.push(num);
        int x =pq_great.top();
        pq_great.pop();
        pq_less.push(x);
        if(pq_less.size()-pq_great.size()>1){
            int y = pq_less.top();
            pq_less.pop();
            pq_great.push(y);
        }
    }
    
    double findMedian() {
        if(pq_less.size()>pq_great.size()){
            return pq_less.top();
        }else{
            return (pq_less.top()+pq_great.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();
 */
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值