Sorted List with Binary Search Insert
Intuition
The simplest approach is to maintain a sorted list of all numbers. When adding a new number, use binary search to find the correct insertion position and insert it to keep the list sorted. Finding the median is then an O(1) lookup of the middle element(s). However, the insertion itself is O(n) because shifting elements in an array is linear.
Algorithm
- Maintain a sorted array of all added numbers.
- **addNum:** Use binary search to find the insertion index, then insert the number at that position.
- **findMedian:** If the array has odd length, return the middle element. If even, return the average of the two middle elements.
O(n) for `addNum` (binary search is O(log n) but insertion is O(n)); O(1) for `findMedian`SpaceO(n) to store all numbersCode (C++ · Java · Python · Go)
class MedianFinder {
vector<int> sorted;
public:
MedianFinder() {}
void addNum(int num) {
auto it = lower_bound(sorted.begin(), sorted.end(), num);
sorted.insert(it, num);
}
double findMedian() {
int n = sorted.size();
if (n % 2 == 1) {
return sorted[n / 2];
}
return (sorted[n / 2 - 1] + sorted[n / 2]) / 2.0;
}
};class MedianFinder {
private List<Integer> sorted;
public MedianFinder() {
sorted = new ArrayList<>();
}
public void addNum(int num) {
int idx = Collections.binarySearch(sorted, num);
if (idx < 0) idx = -(idx + 1);
sorted.add(idx, num);
}
public double findMedian() {
int n = sorted.size();
if (n % 2 == 1) {
return sorted.get(n / 2);
}
return (sorted.get(n / 2 - 1) + sorted.get(n / 2)) / 2.0;
}
}import bisect
class MedianFinder:
def __init__(self):
self.sorted = []
def addNum(self, num: int) -> None:
bisect.insort(self.sorted, num)
def findMedian(self) -> float:
n = len(self.sorted)
if n % 2 == 1:
return float(self.sorted[n // 2])
return (self.sorted[n // 2 - 1] + self.sorted[n // 2]) / 2.0import "sort"
type MedianFinder struct {
sorted []int
}
func Constructor() MedianFinder {
return MedianFinder{sorted: []int{}}
}
func (mf *MedianFinder) AddNum(num int) {
idx := sort.SearchInts(mf.sorted, num)
mf.sorted = append(mf.sorted, 0)
copy(mf.sorted[idx+1:], mf.sorted[idx:])
mf.sorted[idx] = num
}
func (mf *MedianFinder) FindMedian() float64 {
n := len(mf.sorted)
if n%2 == 1 {
return float64(mf.sorted[n/2])
}
return float64(mf.sorted[n/2-1]+mf.sorted[n/2]) / 2.0
}