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  */

 

posted @ 2021-04-15 15:00  habibah_chang  阅读(54)  评论(0编辑  收藏  举报