题目:
中位数是有序列表中间的数。如果列表长度是偶数,中位数则是中间两个数的平均值。
例如,
[2,3,4] 的中位数是 3
[2,3] 的中位数是 (2 + 3) / 2 = 2.5
设计一个支持以下两种操作的数据结构:
void addNum(int num) - 从数据流中添加一个整数到数据结构中。
double findMedian() - 返回目前所有元素的中位数。
思路:
定义大顶堆和小顶堆,大顶堆的最大值始终比小顶堆的最小值要小,两个堆的长度要么相同,要么之间相差一个。
这样当大小顶堆的长度相同时,两个堆顶即为数组中间的两位数字,直接取两个堆的堆顶再除2即可得到中位数,当大小不同时,取长度大的堆的堆顶即可。
代码实现如下
class MedianFinder {
PriorityQueue<Double> maxHeap ;
PriorityQueue<Double> minHeap;
public MedianFinder() {
//大顶堆
maxHeap= new PriorityQueue<Double>(new Comparator<Double>()
{
public int compare(Double o1, Double o2)
{
return o2.compareTo(o1); //表示降序
}
});
//默认小顶堆
minHeap=new PriorityQueue<Double>();
}
public void addNum(int num) {
double n=num*1.0;
if(maxHeap.isEmpty()){
maxHeap.offer(n);
return;
}
//长度相同时 只要比大顶堆大即加入到小顶堆
if(maxHeap.size()==minHeap.size()){
if(n<maxHeap.peek()){
maxHeap.offer(n);
}
else{
minHeap.offer(n);
}
}
//大顶堆长度大时 如果加入的值比大顶堆的值小时 将大顶堆的堆顶加入小顶堆 再把加入的数加进大顶堆
else if(minHeap.size()<maxHeap.size()){
if(n>maxHeap.peek()){
minHeap.offer(n);
}
else{
minHeap.offer(maxHeap.peek());
maxHeap.poll();
maxHeap.offer(n);
}
}
//与上面相反
else if(minHeap.size()>maxHeap.size()){
if(n<minHeap.peek()){
maxHeap.offer(n);
}
else{
maxHeap.offer(minHeap.peek());
minHeap.poll();
minHeap.offer(n);
}
}
}
//取中位数
public double findMedian() {
if((maxHeap.size()+minHeap.size())%2==0){
return ((maxHeap.peek()+minHeap.peek())/2.0);
}
else {
if(maxHeap.size()>minHeap.size()){
return maxHeap.peek();
}
else{
return minHeap.peek();
}
}
}
}