思路:
维护一个大根堆和一个小根堆,大根堆中放的是小数,小根堆中放的是大树,这样中位数就在大根堆和小根堆中堆顶中间作用
怎么理解呢,试想最简单的查找方法是什么,是排序,然后找到中位数,复杂度是O(N^2)
我们现在想象一下,中位数不就是排序后前一半数和后一半数中间的数吗。那我们现在不排序,使用堆,代码中用优先级队列表示。我们大根堆放小数,大根堆堆顶就是小数中最大的数;小根堆放大树,小根堆堆顶是大数中最小的数。那么中位数不就是两个堆顶中间产生吗,要么是前面那个数(大根堆堆顶,当然前提是均衡),要么是平均数(大根堆小根堆堆顶平均数)
下面java代码
class MedianFinder {
PriorityQueue <Integer> minHeap;
PriorityQueue <Integer> maxHeap;
/** initialize your data structure here. */
public MedianFinder() {
this.minHeap= new PriorityQueue <>();
this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() {
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
}
public void addNum(int num) {
//小根堆中的堆顶大于大根堆中的数
if(num<findMedian()){
//当前加入的数比中位数小,应该放前面那个大根堆中去
maxHeap.add(num);
}
else{
minHeap.add(num);
}
//设置是不允许大堆数目比小堆数目多
if(maxHeap.size()>minHeap.size()){
minHeap.add(maxHeap.poll());
}
//设置允许小堆数目比大堆数目最多多1个结点
if(minHeap.size()-maxHeap.size()>1){
maxHeap.add(minHeap.poll());
}
}
public double findMedian() {
if(maxHeap.isEmpty()&&minHeap.isEmpty())
return 0;
if(maxHeap.size()==minHeap.size())
return 1.0*(maxHeap.peek()+minHeap.peek())/2.0;
else
return minHeap.peek();//这一个就是说我始终在小根堆里面多放一个数,如果个数为奇数
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
注意,兄弟们
代码中findMedian()后面的return 为什么是返回小根堆堆顶呢???
因为设置的是在addNum中,就是要小堆始终比大堆最多多放一个,而大堆数目不允许比小堆中数多。这样有什么用呢,就是说,中位数要么是平均数(俩堆数目相等),要么是小堆中堆顶(奇数个数,小堆多放一个,你说中位数在哪里)
那有人问了,我可不可以让大堆多放一个?那是显而易见的可以啊
下面贴出代码
class MedianFinder {
PriorityQueue <Integer> minHeap;
PriorityQueue <Integer> maxHeap;
/** initialize your data structure here. */
public MedianFinder() {
this.minHeap= new PriorityQueue <>();
this.maxHeap= new PriorityQueue <>(new Comparator<Integer>() {
public int compare(Integer o1,Integer o2){
return o2-o1;
}
});
}
public void addNum(int num) {
//小根堆中的堆顶大于大根堆中的数
if(num<findMedian()){
//当前加入的数比中位数小,应该放前面那个大根堆中去
maxHeap.add(num);
}
else{
minHeap.add(num);
}
//设置是不允许大堆数目比小堆数目多
if(maxHeap.size()-minHeap.size()>1){
minHeap.add(maxHeap.poll());
}
//设置允许小堆数目比大堆数目最多多1个结点
if(minHeap.size()-maxHeap.size()>0){
maxHeap.add(minHeap.poll());
}
}
public double findMedian() {
if(maxHeap.isEmpty()&&minHeap.isEmpty())
return 0;
if(maxHeap.size()==minHeap.size())
return 1.0*(maxHeap.peek()+minHeap.peek())/2.0;
else
return maxHeap.peek();//这一个就是说我始终在小根堆里面多放一个数,如果个数为奇数
}
}
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder obj = new MedianFinder();
* obj.addNum(num);
* double param_2 = obj.findMedian();
*/
注意到了吗,我只改了参数罢了,其他都没动