题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路:
在非递减排序中,中位数左边的数一定不会大于它,右边的数一定不会小于它,同时左边的数目和右边的数目相等
左边的数一定不会大于它,我们可以用一个大顶堆
右边的数一定不会小于它,我们可以用一个小顶堆
如何使左右数目相等,我们好像做不到,但是我们可以使他们数目相差不会超过1,比如奇数位置时扔进大顶堆,偶数位置时扔进小顶堆。
这样当有奇数个数时,大顶堆的数目比小顶堆多1,大顶堆的堆顶就是中位数;有偶数个数时,大顶堆的数目和小顶堆的数目相等,大顶堆和小顶堆的堆顶的平均数就是中位数。
但是这个实现思路和分析思路是等价的吗?不是。
我们还需要保证大顶堆的最大值不大于小顶堆的最小值,所以在插入的时候需要判断处理一下
import java.util.*;
public class Solution {
PriorityQueue<Integer> mn=new PriorityQueue<Integer>();
PriorityQueue<Integer> mx=new PriorityQueue<Integer>(new Comparator<Integer>(){
public int compare(Integer a,Integer b){
return b-a;
}
});
int cnt=0;
public void Insert(Integer num) {
cnt++;
if(cnt%2==0){
if(!mx.isEmpty()&&num<mx.peek()){
mx.offer(num);
num=mx.poll();
}
mn.offer(num);
}
else{
if(!mn.isEmpty()&&num>mn.peek()){
mn.offer(num);
num=mn.poll();
}
mx.offer(num);
}
}
public Double GetMedian() {
if(cnt%2==0){
return (mx.peek()+mn.peek())/2.0;
}
else{
return 1.0*mx.peek();
}
}
}