I did this
public class MedianFinder {
private readonly PriorityQueue<int, int> minHeap;
private readonly PriorityQueue<int, int> maxHeap;
public MedianFinder() {
minHeap = new PriorityQueue<int, int>();
maxHeap = new PriorityQueue<int, int>(Comparer<int>.Create((a,b) => b.CompareTo(a)));
}
public void AddNum(int num) {
if (maxHeap.Count == 0) {
maxHeap.Enqueue(num, num);
return;
}
//Case 1 - maxHeap greater
if (maxHeap.Count > minHeap.Count) {
if (maxHeap.Peek() > num) {
int maxTop = maxHeap.Dequeue();
maxHeap.Enqueue(num, num);
minHeap.Enqueue(maxTop, maxTop);
}
else minHeap.Enqueue(num, num);
}
//Case 2 - minHeap greater
else if (minHeap.Count > maxHeap.Count) {
if (minHeap.Peek() < num) {
int minTop = minHeap.Dequeue();
minHeap.Enqueue(num, num);
maxHeap.Enqueue(minTop, minTop);
}
else maxHeap.Enqueue(num, num);
}
//Case 3 - both equal
else {
if (minHeap.Peek() <= num)
minHeap.Enqueue(num, num);
else
maxHeap.Enqueue(num, num);
}
}
public double FindMedian() {
if (minHeap.Count > maxHeap.Count)
return minHeap.Peek();
else if (maxHeap.Count > minHeap.Count)
return maxHeap.Peek();
else
return ((long)minHeap.Peek() + maxHeap.Peek()) / 2.0;
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.AddNum(num);
* double param_2 = obj.FindMedian();
*/This cleaner one works,
public class MedianFinder {
private readonly PriorityQueue<int, int> low =
new(Comparer<int>.Create((a, b) => b.CompareTo(a))); // max-heap: lower half
private readonly PriorityQueue<int, int> high = new(); // min-heap: upper half
public void AddNum(int num) {
low.Enqueue(num, num); // 1. put it in the lower half
int top = low.Dequeue(); // 2. move the lower half's largest up, so every value in low <= every value in high
high.Enqueue(top, top);
if (high.Count > low.Count) { // 3. rebalance: low is always equal in size or one bigger
int t = high.Dequeue();
low.Enqueue(t, t);
}
}
public double FindMedian() =>
low.Count > high.Count
? low.Peek() // odd count: the middle is low's top
: (low.Peek() + (double)high.Peek()) / 2; // even count: average of both tops
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.AddNum(num);
* double param_2 = obj.FindMedian();
*/The idea: low holds the smaller half (max-heap), high holds the larger half (min-heap). The median is always at the tops. Two rules must hold after every add:
- Everything in
low≤ everything inhigh. lowhas the same size ashigh, or one more.
public void AddNum(int num) {
low.Enqueue(num, num); // step 1
int top = low.Dequeue(); // step 2
high.Enqueue(top, top);
if (high.Count > low.Count) { // step 3
int t = high.Dequeue();
low.Enqueue(t, t);
}
}Steps 1 and 2: guarantee rule 1. Push num into low, then pop low’s largest and send it to high. Whatever stays in low is smaller than or equal to what was just sent up, so the halves are correctly separated. You never compare num against anything, because the max-heap does the comparing.
Step 3: guarantee rule 2. Steps 1 and 2 net out to high gaining one element and low staying the same size. If high is now bigger than low, move high’s smallest back to low.