295 Find Median from Data Stream

1 题目

Median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value. So the median is the mean of the two middle value.

For example,

[2,3,4], the median is 3

[2,3], the median is (2 + 3) / 2 = 2.5

Design a data structure that supports the following two operations:

  • void addNum(int num) - Add a integer number from the data stream to the data structure.
  • double findMedian() - Return the median of all elements so far.

Example:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2

2 尝试解

2.1 分析

连续输入一组数字,在输入过程中可能要求返回当前已输入数字的中位数。

用一个最大堆smaller和一个最小堆larger分别存储,且满足以下两个性质

  • 两个堆的尺寸相差不超过1
  • larger的任意元素均不小于smaller的任意元素,即smaller.top() <= larger.top()

由于两个堆的尺寸相差不超过1,所以中位数一定由两个堆的堆顶元素决定。具体插入操作如下,如果最小堆larger不为空且插入的数num > larger.top(),说明该数一定比中位数大,所以将该数放入larger中,否则存入smaller中。然后检查两个堆的尺寸是否仍相差不超过1,如果不是,那么将尺寸更大的堆的堆顶元素压入另一个堆中,同时从原堆中删去该元素。在整个插入完成后,以上两个性质仍然满足,中位数仍由两个堆的堆顶元素决定。

P.S. smaller.size() - larger.size()操作在前者小于后者的情况下会出问题,因为该类型是无符号整数。

2.2 代码

class MedianFinder {
public:
    /** initialize your data structure here. */
    priority_queue<int,vector<int>,greater<int>> minheap;
    priority_queue<int,vector<int>,less<int>> maxheap;
    MedianFinder() {
    }
    
    void addNum(int num) {
        if(minheap.size() && num >= minheap.top())
            minheap.push(num);
        else
            maxheap.push(num);
        while(minheap.size()>1+maxheap.size()){
            maxheap.push(minheap.top());
            minheap.pop();
        }
        while(maxheap.size()>1+minheap.size()){
            minheap.push(maxheap.top());
            maxheap.pop();
        }
    }
    
    double findMedian() {
        if(minheap.size() == maxheap.size())
            return (double(minheap.top())+double(maxheap.top()))/2;
        else
            return double(minheap.size()>maxheap.size()?minheap.top():maxheap.top());
    }
};

3 标准解

3.1 分析

上述方法的复杂度为O(lg N),是最优方法。另外一种最优方法为平衡二叉搜索树。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值