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 theMedianFinderobject.void addNum(int num)adds the integernumfrom the data stream to the data structure.double findMedian()returns the median of all elements so far. Answers within10-5of 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 * 104calls will be made toaddNumandfindMedian.
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 valuenumin mind), we pushnumintomaxHeapand 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 valuenumin mind), we pushnumintominHeapand push the top of it intomaxHeap.