295. Find Median from Data Stream
问题:
设计结构体,能够满足以下两个功能:
- 向结构体中插入数据 void addNum(int num)
- 去当前结构体中的中位数 double findMedian()
- 若共有奇数个数,取最中间的数
- 若共有偶数个数,取中间两个数之和/2
Example 1: Input ["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"] [[], [1], [2], [], [3], []] Output [null, null, null, 1.5, null, 2.0] Explanation MedianFinder medianFinder = new MedianFinder(); medianFinder.addNum(1); // arr = [1] medianFinder.addNum(2); // arr = [1, 2] medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2) medianFinder.addNum(3); // arr[1, 2, 3] medianFinder.findMedian(); // return 2.0 Constraints: -10^5 <= num <= 10^5 There will be at least one element in the data structure before calling findMedian. At most 5 * 10^4 calls will be made to addNum and findMedian. Follow up: If all integer numbers from the stream are in the range [0, 100], how would you optimize your solution? If 99% of all integer numbers from the stream are in the range [0, 100], how would you optimize your solution?
解法:priority_queue, heap(优先队列,最大堆,最小堆)
思路:
要求中位数,即一堆数排序后,最中间的一个or两个数。
那么我们可以考虑,使用两个heap,
- 一个记录最小的一半数。smaller
- 一个记录最大的一半数。larger
那么中位数,只相关于:smaller中最大的,larger中最小的数。
因此 smaller使用最大堆,larger使用最小堆,
这样,top即为所求相关数。
我们考虑如何插入:
- 要保证smaller和larger各保存一半数据。
- 🌟 数据个数==奇数时,larger方保存更多的一个。
那么,若当前有偶数个数:
新插入的数需要最终插入larger方,
因此我们先将其插入smaller方->smaller中会推出一个最大值,将这个最大值,再最终插入larger方。
若当前有奇数个数:(lager方一定多一个)
新插入的数需要最终插入smaller方,
因此我们先将其插入larger方->larger方会推出一个最小值,再将这个最小值,最终插入smaller方。
⚠️ 注意:记得同时更新总个数的奇偶性,even=!even
那么所求中位数为:
- 数据总个数==奇数:
- larger方的top(由于🌟 )
- 数据总个数==偶数:
- (smaller方top+larger方top) / 2
代码参考:
1 class MedianFinder { 2 public: 3 /** initialize your data structure here. */ 4 MedianFinder() { 5 6 } 7 8 void addNum(int num) { 9 if(even) { 10 //first to insert to lager queue. 11 smaller.push(num); 12 larger.push(smaller.top()); 13 smaller.pop(); 14 } else { 15 larger.push(num); 16 smaller.push(larger.top()); 17 larger.pop(); 18 } 19 even = !even; 20 } 21 22 double findMedian() { 23 if(even) { 24 return ( smaller.top()+larger.top() ) / 2.0; 25 } else { 26 return larger.top(); 27 } 28 } 29 private: 30 priority_queue<int, vector<int>, greater<int>> larger;//top->smallest element 31 priority_queue<int> smaller;//top->largest element 32 bool even=true; 33 }; 34 35 /** 36 * Your MedianFinder object will be instantiated and called as such: 37 * MedianFinder* obj = new MedianFinder(); 38 * obj->addNum(num); 39 * double param_2 = obj->findMedian(); 40 */