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

题目描述:

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

思路:

数据流中的数据需要用合适的容器存放。

方法1:用数组

用数组存放是比较直接的方法,将新数据插入一个数组的时间复杂度是O(1),从中找中位数可以用partition的方法(参考:数组中出现次数超过一半的数字),时间复杂度是O(n)。但是数组有个问题是必须事先指定长度。

方法2:用堆

数据被中位数分为两半,用一个最大堆和一个最小堆,各存放一半的数字,且最大堆中数字都小于最小堆中数字。则最大堆存放的是中位数左边的数字,最小堆中存放的是中位数右边的数字。

具体实现的时候,为了保证两个堆中数字平均分配,可以在数据总数为偶数时将新数据放进最小堆中,数据总数为寄数时将新数据放进最大堆中。但是要保证新数据放进去之后最大堆中的数字都比最小堆中数字小,所以在将新数据放进最小堆之前,先要判断新数据是不是比最大堆中数据都大,最大堆堆顶的数据是最大的数据,要是新数据比堆顶数据还大,就可以直接放入最小堆,要是新数据比堆顶数据小,那就先把新数据放进最大堆,然后把新的最大堆中的最大数取出来放进最小堆。将新数据放入最大堆之前也要进行类似的判断。

注意:我们采用vector容器和stl中的函数push_heap,pop_heap实现堆,用less和greater函数实现最大最小堆。

每次插入元素后调用push_heap(maxHeap.begin(),maxHeap.end(),less<int>())对插入的元素做堆排序,默认使用less<int>表示将最大元素放在第一个位置。如果要删除堆顶元素,先调用pop_heap(maxHeap.begin(),maxHeap.end(),less<int>()),将堆顶元素与end前的元素(即最后一个元素)交换,然后将除了最后一个元素之外的元素重新进行堆排序。

参考代码:

在线测试

https://www.nowcoder.com/practice/9be0172896bd43948f8a32fb954e1be1?tpId=13&tqId=11216&tPage=1&rp=1&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking

AC代码

class Solution {
public:
    void Insert(int num)
    {
        if(((maxHeap.size()+minHeap.size())&1)==0)
        {
            if(!maxHeap.empty()&&num<maxHeap[0])
            {
                maxHeap.push_back(num);
                push_heap(maxHeap.begin(),maxHeap.end(),less<int>());
                num=maxHeap[0];
                pop_heap(maxHeap.begin(),maxHeap.end(),less<int>());
                maxHeap.pop_back();
            }
            minHeap.push_back(num);
            push_heap(minHeap.begin(),minHeap.end(),greater<int>());
        }
        else
        {
            if(!minHeap.empty()&&num>minHeap[0])
            {
                minHeap.push_back(num);
                push_heap(minHeap.begin(),minHeap.end(),greater<int>());
                num=minHeap[0];
                pop_heap(minHeap.begin(),minHeap.end(),greater<int>());
                minHeap.pop_back();
            }
            maxHeap.push_back(num);
            push_heap(maxHeap.begin(),maxHeap.end(),less<int>());
        }
    }

    double GetMedian()
    {
        if((maxHeap.size()+minHeap.size())&1)
        {
            return minHeap[0];
        }
        else
            return (minHeap[0]+maxHeap[0])/2.0;
    }
private:
    vector<int> maxHeap;
    vector<int> minHeap;
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值