题目描述:
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。
思路分析:
- 如果数字个数为偶数,中位数为中间的2个数的平均数,如:1,2,3,4,中位数为(2+3)/ 2 = 2.5
- 如果数字个数为奇数,中位数为中间的数。如:1, 2, 3,中位数为 2;
前提是数字先排好序。
我们可以把数字分为2部分:前半部分和后半部分,前半部分用大顶堆B存储,则最大值在堆顶,后半部分用小顶堆A存储,则最小值在堆顶,则:
A.size() == B.size
return (A.peek() + B.peek()) / 2;
A.size() != B.size
return A.peek();
参考代码:
class MedianFinder {
private Queue<Integer> A;
private Queue<Integer> B;
public MedianFinder() {
this.A = new PriorityQueue();//小顶堆
this.B = new PriorityQueue<>((x, y) -> (y - x));//大顶堆
}
public void addNum(int num) {
if(A.size() == B.size()){
B.add(num);
A.add(B.poll());
}
else{
A.add(num);
B.add(A.poll());
}
}
public double findMedian() {
return A.size() == B.size() ? (A.peek() + B.peek()) / 2.0 : (double)A.peek();
}
}
注意:
-
A.size() != B.size()时,向B添加元素,此时元素可能属于后半部分,所以先将元素添加到A中,然后把A的堆顶元素(最小的元素)出堆后放入B中。
-
A.size() == B.size()时,向A添加元素,此时元素可能属于前半部分,所以先将元素添加到B中,然后把B的堆顶元素(最大的元素)出堆后放入A中。