295. 数据流的中位数

    xiaoxiao2024-10-27  74

    题目描述: 

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

    例如,

    [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,两个堆size一样,新元素<最大堆堆顶,压入最大堆,否则压入最小堆情况2,最大堆比最小堆多一个元素 新元素>最大堆堆顶,直接压入最小堆维持平衡新元素<最大堆堆顶,此时复杂,将最大堆堆顶push到最小堆,再pop最大堆,最后压入新元素到最大堆情况3,最大堆比最小堆少一个元素 新元素<最小堆堆顶,直接压入最大堆新元素>最小堆堆顶,最小堆堆顶push到最大堆,然后pop最小堆,最后压入新元素到最小堆

    返回值就是size相同,堆顶加和/2,否则谁size大,返回谁堆顶 复杂度:找中位数O(1),加元素O( logN)

    class MedianFinder { priority_queue<int, vector<int>, less<int>>q1; priority_queue<int, vector<int>, greater<int>>q2; public: /** initialize your data structure here. */ MedianFinder() { } void addNum(int num) { if(((q1.size() + q2.size()) % 2) == 0) { if(q2.empty()) q2.push(num); else if(num < q1.top()) { q2.push(q1.top()); q1.pop(); q1.push(num); } else q2.push(num); } else { if(num > q2.top()) { q1.push(q2.top()); q2.pop(); q2.push(num); } else { q1.push(num); } } } double findMedian() { if(((q1.size() + q2.size()) % 2) == 0) { if(q1.size() + q2.size() == 0) return 0.0; else return ((q1.top() + q2.top()) / 2. ); } else return (double)q2.top(); } }; /** * Your MedianFinder object will be instantiated and called as such: * MedianFinder* obj = new MedianFinder(); * obj->addNum(num); * double param_2 = obj->findMedian(); */

    关于进阶:

    参考:Leetcode:数据流的中位数

    最新回复(0)