中位数是有序整数列表中的中间值。如果列表的大小是偶数,则没有中间值,中位数是两个中间值的平均值。
- 例如
arr = [2,3,4]的中位数是3。 - 例如
arr = [2,3]的中位数是(2 + 3) / 2 = 2.5。
实现 MedianFinder 类:
-
MedianFinder()初始化MedianFinder对象。 -
void addNum(int num)将数据流中的整数num添加到数据结构中。 -
double findMedian()返回到目前为止所有元素的中位数。与实际答案相差10-5以内的答案将被接受。
示例 1:
输入
["MedianFinder", "addNum", "addNum", "findMedian", "addNum", "findMedian"]
[[], [1], [2], [], [3], []]
输出
[null, null, null, 1.5, null, 2.0]
解释
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1); // arr = [1]
medianFinder.addNum(2); // arr = [1, 2]
medianFinder.findMedian(); // 返回 1.5 ((1 + 2) / 2)
medianFinder.addNum(3); // arr[1, 2, 3]
medianFinder.findMedian(); // return 2.0
一、双堆法
思路:
用两个堆来分别存一半的较小和较大的数,大顶堆允许比小顶堆最多多一个元素。
小顶堆存较大一半的数,堆顶是较大数中的最小值。
大顶堆存较小一半多数,堆顶是较小数中的最大值。
这样中位数就可以通过取两个堆的堆顶元素来计算获得。
通过判断元素和堆顶元素的大小来添加进不同的堆,那怎么调整两个堆是元素数量呢?
直接比较,如果小顶堆的元素数量比大顶堆多了1(只会多1,因为每次插入元素都会判断),就直接把小顶堆的堆顶元素移除并加到大顶堆中。
时间复杂度O(log n)
代码:
java
class MedianFinder {
private PriorityQueue<Integer> minHeap;
private PriorityQueue<Integer> maxHeap;
public MedianFinder() {
minHeap = new PriorityQueue<>();
maxHeap = new PriorityQueue<>(Collections.reverseOrder());
}
public void addNum(int num) {
if(!maxHeap.isEmpty() && num < maxHeap.peek()){
maxHeap.offer(num);
}else{
minHeap.offer(num);
}
// 平衡两个堆的数量
if(maxHeap.size() > minHeap.size() + 1){
minHeap.offer(maxHeap.poll());
}else if(minHeap.size() > maxHeap.size()){
maxHeap.offer(minHeap.poll());
}
}
public double findMedian() {
if(maxHeap.size() == minHeap.size() + 1){
return maxHeap.peek();
}else{
return (maxHeap.peek() + minHeap.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();
*/