Leetcode295 数据流中的中位数-最小堆和最大堆
題目
中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。
例如,[2,3,4] 的中位數是 3;[2,3] 的中位數是 (2 + 3) / 2 = 2.5
設計一個支持以下兩種操作的數據結構:
void addNum(int num) - 從數據流中添加一個整數到數據結構中。
double findMedian() - 返回目前所有元素的中位數。
示例:
進階:
如果數據流中所有整數都在 0 到 100 范圍內,你將如何優化你的算法?
如果數據流中 99% 的整數都在 0 到 100 范圍內,你將如何優化你的算法?
來源:力扣(LeetCode)
鏈接:Leetcode295 數據流中的中位數
思路
優化解法,動態維護一個最大堆和一個最小堆。各存放一半數據,要求:最大堆的堆頂元素要比最小堆的堆頂元素小(這樣,最大堆里面的元素都比最小堆里面的值小)。
priority_queue<int> big_queue;//默認最大堆priority_queue< int,vector<int>,greater<int>> small_queue;//最小堆構造按照最大堆和最小堆中元素個數分為三種情況討論:無非相等,最大堆元素多一個,最小堆元素對一個三種情況。當新來的元素num來的時候,即遇到如下三種情況分析:
使之滿足最小堆和最大堆滿足:元素個數相等,或者最大堆元素多一個,或者最小堆元素多一個。這樣中位數便可以在堆頂元素取得。無非是取平均值或者某一個堆頂元素。
代碼
class MedianFinder { public:/** initialize your data structure here. */MedianFinder() {}void addNum(int num) {if(big_queue.empty())//堆為空時,這里其實保證了兩個隊大小基本一樣{big_queue.push(num);return;}if(big_queue.size()==small_queue.size())//最大堆大小==最小堆大小{if(num<big_queue.top())big_queue.push(num);elsesmall_queue.push(num);}else if(big_queue.size()>small_queue.size())//最大堆大小>最小堆{if(num>big_queue.top())small_queue.push(num);else {small_queue.push(big_queue.top());big_queue.pop();big_queue.push(num);}}else if(big_queue.size()<small_queue.size())//最大堆大小<最小堆{if(num>small_queue.top()){small_queue.push(num);big_queue.push(small_queue.top());small_queue.pop();}else{big_queue.push(num);}}}double findMedian() {if(big_queue.size()==small_queue.size())//偶數時,返回兩者平均值return (small_queue.top()+big_queue.top())/2.0;else if(big_queue.size()>small_queue.size())return big_queue.top();return small_queue.top();}private:priority_queue<int> big_queue;priority_queue< int,vector<int>,greater<int>> small_queue; };/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder* obj = new MedianFinder();* obj->addNum(num);* double param_2 = obj->findMedian();*/測試結果:
總結
最小堆和最大堆結合,這樣可以提高算法速度。比直觀的使用數組排序并且查找中位數要快很多。
總結
以上是生活随笔為你收集整理的Leetcode295 数据流中的中位数-最小堆和最大堆的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 千层饼家常做法?
- 下一篇: Leetcode376摇摆序列--贪心+