0
点赞
收藏
分享

微信扫一扫

【LeetCode 295】. 数据流的中位数

船长_Kevin 2022-02-16 阅读 52

中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2
进阶:

如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?

解题报告:

对顶堆的完美应用。

注意点1:在对顶堆启动阶段的时候,只需要判断其中一个堆是否为空就好了,不需要两个都有值。

注意点2:把push元素和堆大小的维护给拆成两个原子操作,便于理解,也便于每一部分代码做唯一的事情。

AC代码:

class MedianFinder {
public:
    priority_queue<int> q1;//大根堆
    priority_queue<int, vector<int>, greater<int>> q2;//小根堆
    MedianFinder() {    
    }
    
    void addNum(int num) {
        if(q1.empty()) q1.push(num);
        // else if(q2.empty() && num > q1.top()) q2.push(num);
        else if(num < q1.top()) q1.push(num);
        else q2.push(num);
        
        if((int)q1.size() - (int)q2.size() > 1) {
            int x = q1.top();q1.pop();
            q2.push(x);
        } else if((int)q2.size() - (int)q1.size() > 1) {
            int x = q2.top();q2.pop();
            q1.push(x);
        }
    }
    
    double findMedian() {
        if(q1.size()+q2.size() == 0) return 0;
        if(q1.size() == 0) return q2.top();
        if(q2.size() == 0) return q1.top();
        if(q1.size() < q2.size()) return q2.top();
        else if(q1.size() > q2.size()) return q1.top();
        else return (q1.top()+q2.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();
 */

注意点3:可以人为的做一些约束,限制两个pq的灵活性,来缩短代码量。比如强制要求小根堆的元素多于或等于大跟堆的。

0<=q2.size-q1.size()<=1。

这样实现只需要:

    double findMedian() {
        if (queMin.size() > queMax.size()) {
            return queMin.top();
        }
        return (queMin.top() + queMax.top()) / 2.0;
    }
举报

相关推荐

0 条评论