剑指offer41:数据流中的中位数

 

讲讲这题的几个思路:

1.暴力排序:

emmm也不是纯暴力,我们可以分析一下,以前做数学卷子的时候不是有道统计题可能让我们求中位数什么的,那我们怎么做的?我们是先把数据排个序对吧,一般是从小到大的,然后如果数据个数是偶数就中间两个的平均,如果是奇数就是最中间的。用这个思路实现其实也行,那我们排序用快排时间复杂度是O(nlogn),求平均的时间复杂度是常量,所以总的复杂度就是O(nlogn),不错的做法嘿嘿。

2.链表:

插入排序O(n),求中位数O(n),总的时间复杂度是O(n),这样看链表优点拉了

3.堆:

这题用堆或许就是最巧妙的做法了吧。。。试想一下,我们要求中位数需要的是什么?是不是只需要排序的最中间的数或者中间两个数的平均,那我们可不可以用一种数据结构来实现一种划分而不是真正的排序?维护一个大小均衡一点的最大堆和最小堆即可,是不是很有感觉了?

用一个最大堆实现前半部分的数据存储,一个最小堆实现后半部分的数据存储,我们要让他们之间的大小差异不超过1。

实现的代码如下:

class MedianFinder {
public:
    priority_queue<int,vector<int>,less<int>> maxHeap;//大顶堆
    priority_queue<int,vector<int>,greater<int>> minHeap;//小顶堆
    /** initialize your data structure here. */
    MedianFinder() {

    }
    
    void addNum(int num) {
        if(maxHeap.size()==minHeap.size())//堆的大小相等时 优先加到最小堆
        {
            maxHeap.push(num);
            minHeap.push(maxHeap.top());
            maxHeap.pop();
        }
        else if(maxHeap.size()>minHeap.size())
        {
            maxHeap.push(num);
            minHeap.push(maxHeap.top());
            maxHeap.pop();
        }
        else
        {
            minHeap.push(num);
            maxHeap.push(minHeap.top());
            minHeap.pop();
        }
    }
    
    double findMedian() {
        if(maxHeap.size()==minHeap.size())
        {
            return (maxHeap.top()+minHeap.top())/2.0;
        }
        else if(maxHeap.size()>minHeap.size())
        {
            return maxHeap.top()/1.0;
        }
        else if(maxHeap.size()<minHeap.size())
        {
            return minHeap.top()/1.0;
        }
        return 0;
    }
};

这里面的细节:

1.我们是怎么实现往哪个堆里面添加元素的呢,求中间的数,那肯定是对半分大小,哪个小往哪个添。那相等怎么办?那不是随便添,你自己想往哪里添就往哪里添。。。

2.还有,如何维护两个堆的关系,我们知道,最小堆维护的是右半部分的大的数据的存储,最大堆相反,实质上维护两个堆的关系是让最小堆的栈顶元素大于等于最大堆的最大元素,这样就能恒定保持最小堆里的数都是大于等于最大堆里面的数的

3.如何实现2?这里用到堆的很巧妙的性质,比如说我要往右边(最小堆)里添加,不是直接push,而是先用最大堆选出包括num在内的最大元素,压入最小堆,再pop掉最大堆的顶,那这样就实现了堆关系的维护

结果如下所示:

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值