Find Median from Data Stream
Problem
The median is the middle value in an ordered integer list. If the size of the list is even, there is no middle value and the median is the mean of the two middle values.
- For example, for
arr = [2,3,4]
, the median is3
. - For example, for
arr = [2,3]
, the median is(2 + 3) / 2 = 2.5
.
Implement the MedianFinder class:
MedianFinder()
initializes theMedianFinder
object.void addNum(int num)
adds the integernum
from the data stream to the data structure.double findMedian()
returns the median of all elements so far. Answers within10-5
of the actual answer will be accepted.
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:
-105 <= num <= 105
- There will be at least one element in the data structure before calling
findMedian
. - At most
5 * 104
calls will be made toaddNum
andfindMedian
.
Solution
class MedianFinder {
constructor() {
// invariant: minHeap.size() >= maxHeap.size()
this.maxHeap = new MaxPriorityQueue();
this.minHeap = new MinPriorityQueue();
this.evenSize = true; // is there an even number of elements
}
addNum(num) {
if (this.evenSize) {
this.maxHeap.enqueue(num);
this.minHeap.enqueue(this.maxHeap.dequeue().element);
} else {
this.minHeap.enqueue(num);
this.maxHeap.enqueue(this.minHeap.dequeue().element);
}
this.evenSize = !this.evenSize;
}
findMedian() {
if (this.minHeap.isEmpty()) {
return 0.0;
} else if (this.evenSize) {
return (this.minHeap.front().element + this.maxHeap.front().element) / 2.0;
} else {
return this.minHeap.front().element;
}
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* var obj = new MedianFinder()
* obj.addNum(num)
* var param_2 = obj.findMedian()
*/
We will use two heaps, a min-heap minHeap
and a max-heap maxHeap
; such that minHeap
contains the larger half of all the values added, and maxHeap
contains the smaller half of all the values added (ie. cycle between adding to the minHeap
and maxHeap
). Thus, the median is either the top
value in minHeap
, or the average top
value of minHeap
and maxHeap
(depending on if there is an even or odd number of values). For the addNum
method, in order to keep the previously mentioned property, there are two cases that needs to be considered:
- If there is currently an even number of values (ie.
minHeap.size() == maxHeap.size()
), we want the value in range[maxHeap.top(), minHeap.top())
to be pushed intominHeap
. Thus, to find this value (while also keeping the new valuenum
in mind), we pushnum
intomaxHeap
and push the top of it intominHeap
. - If there is currently an odd number of values (ie.
minHeap.size() > maxHeap.size()
), we want the value in range(maxHeap.top(), minHeap.top()]
to be pushed intomaxHeap
. Thus, to find this value (while also keeping the new valuenum
in mind), we pushnum
intominHeap
and push the top of it intomaxHeap
.