The problem involves finding the median of a stream of integers in real-time. The median is the middle value in a sorted list of numbers, or the average of the two middle values if the list has an even number of elements.
To solve this efficiently, we use two heaps:
The heaps are balanced such that the size difference between them is at most 1. This allows us to calculate the median in constant time by looking at the top elements of the heaps.
class MedianFinder {
private PriorityQueue<Integer> maxHeap; // Stores the smaller half
private PriorityQueue<Integer> minHeap; // Stores the larger half
public MedianFinder() {
maxHeap = new PriorityQueue<>(Collections.reverseOrder());
minHeap = new PriorityQueue<>();
}
public void addNum(int num) {
// Add to maxHeap first
maxHeap.offer(num);
// Balance heaps: Ensure all elements in maxHeap are <= elements in minHeap
minHeap.offer(maxHeap.poll());
// Maintain size property: maxHeap can have at most one more element than minHeap
if (maxHeap.size() < minHeap.size()) {
maxHeap.offer(minHeap.poll());
}
}
public double findMedian() {
if (maxHeap.size() > minHeap.size()) {
return maxHeap.peek();
} else {
return (maxHeap.peek() + minHeap.peek()) / 2.0;
}
}
}
O(log n)
โ Adding a number to a heap and balancing the heaps both take logarithmic time.O(1)
โ Retrieving the median is a constant-time operation as it only involves peeking at the top elements of the heaps.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 (median of [1, 2])
medianFinder.addNum(3); // arr = [1, 2, 3]
medianFinder.findMedian(); // return 2.0 (median of [1, 2, 3])