题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
分析:可以使用优先队列的大小顶堆来进行排序,进而获得中位数。
具体代码实现如下:
import java.util.*;
public class Solution {
/*
利用优先队列的大小顶堆来实现中位数,大顶堆保存较小的数(那么它的头元素(堆顶)即为较小数中的最大数),
小顶堆保存较大的数(那么它的头元素(堆顶)即为较大数中的最小数)。设共有N=m+n个元素,在添加元素时要保证大小顶堆各一半:
当N为奇数时:m=n+1=(N+1)/2 (m表示小顶堆里面的元素个数)
当N为偶数时:m=n=N/2 (n表示大顶堆里面的元素个数)
故,当m=n时,中位数为:(小顶堆的堆顶元素+大顶堆的堆顶元素)/2
当m≠n时,中位数为:小顶堆的堆顶元素
*/
PriorityQueue<Integer> min = new PriorityQueue<>();;// 小顶堆
PriorityQueue<Integer> max = new PriorityQueue<>((x,y) -> (y - x));// 大顶堆
public void Insert(Integer num) {// 要保证大小顶堆中的元素之差小于等于1
if(min.size() == max.size()){//元素最终需要放入小顶堆中
max.offer(num);// 先放入大顶堆中进行排序
min.offer(max.poll());// 再将大顶堆中堆顶的元素(较小数中最大的元素)放入小顶堆
}else{// 元素最终放入大顶堆中
min.offer(num);// 先放入小顶堆进行排序,比较大小,堆顶为较小数中的最大值
max.offer(min.poll());// 然后再将小顶堆中堆顶的元素(较大数中最小的元素)放入大顶堆
}
}
public Double GetMedian() {// 如果大小顶堆长度不等,则中位数存在于小顶堆的堆顶,否则存在于两个堆顶元素除以2
return min.size() == max.size() ? (min.peek() + max.peek()) / 2.0 : (double)min.peek();
}
}
人生若只如初见,何事秋风悲画扇。
等闲变却故人心,却道故人心易变。
-----------纳兰性德
小白寄语:学如逆水行舟,不进则退。