[leetcode] 295. Find Median from Data Stream

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.

Examples: 

[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.

For example:

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

这道题是找中位数,题目难度为Hard。

找中位数的前提是数字已排序,而这里数字的插入是动态的,最直观的想法是通过二分查找将数字插入到合适位置,然后直接找中位数,尝试了一下竟然直接通过了。具体代码:

class MedianFinder {
    vector<int> data;
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        auto it = lower_bound(data.begin(), data.end(), num);
        data.insert(it, num);
    }

    // Returns the median of current data stream
    double findMedian() {
        if(data.empty()) return 0;
        int sz = data.size();
        if(sz%2) return data[(sz-1)/2];
        else return (data[sz/2-1] + data[sz/2]) / 2.0;
    }
};

虽然从运行时间上看比较可观,不过依赖vector的插入操作,针对vector的插入是比较耗时的,涉及到后面数字的顺序后移,这里可能测试用例数据量还不够大。

还可以将数字分为左右两部分,左半部分存储小的一半数字,右半部分存储大的一半数字,插入数字时在左右两部分间做动态平衡,始终保持两部分数字数量相差1以内,这样找中位数就比较方便了。至此大家应该已经想到了用堆来对实现上述功能,左半部分用大根堆来存储,堆顶元素是左半部分最大的,右半部分用小根堆来存储,堆顶元素是右半部分最小的,始终保持左右两部分数字个数相等或左半部分比右半部分多一个,如果左半部分比右半部分多一个数字,中位数是左半部分堆顶数字;如果左右两部分数字个数相等,中位数是两个堆顶元素之和除以2。c++中priority_queue默认是大根堆,对堆还不太了解的同学可以通过菜单查看相关的题目。另外需要注意的是堆的插入和删除操作复杂度为O(logn),在使用时应该尽量减少插入和删除次数。具体代码:

class MedianFinder {
    priority_queue<int> l;
    priority_queue<int, vector<int>, greater<int>> r;
public:

    // Adds a number into the data structure.
    void addNum(int num) {
        if(l.empty() || num > l.top()) r.push(num);
        else l.push(num);
        
        if(l.size() > r.size()+1) {
            r.push(l.top());
            l.pop();
        }
        else if(l.size() < r.size()) {
            l.push(r.top());
            r.pop();
        }
    }

    // Returns the median of current data stream
    double findMedian() {
        if(l.size() > r.size()) return l.top();
        else return (l.top() + r.top()) / 2.0;
    }
};

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值