题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
题解
首先想到的就是可以用大顶堆小顶堆来解决这个问题;但是队列好久没有使用了,那就得复习一下队列的一些常用方法:
增加:
①add(): 增加一个元索 (如果队列已满,则抛出一个IIIegaISlabEepeplian异常 )
②put(): 添加一个元素 (如果队列满,则阻塞)
③offer(): 添加一个元素并返回true (如果队列已满,则返回false)
移除:
①remove(): 移除并返回队列头部的元素 (如果队列为空,则抛出一个NoSuchElementException异常)
②take(): 移除并返回队列头部的元素 (如果队列为空,则阻塞)
③poll(): 移除并返问队列头部的元素 (如果队列为空,则返回null)
获取:
①element(): 返回队列头部的元素 (如果队列为空,则抛出一个NoSuchElementException异常)
②peek(): 返回队列头部的元素 (如果队列为空,则返回null)
解题思路
大顶堆存放小的数字,从大到小排序、小顶堆存放大的数字,从小到大排序:
用一个count记录当前的次数,从0开始,偶数个的时候先进入大顶堆,然后弹出第一个到小顶堆;奇数个的时候,先进入小顶堆,然后弹出第一个到大顶堆;
读数时:当两个堆的大小一致时,取两者的平均数;当大顶堆大于小顶堆的大小时,返回大顶堆的头部;当小顶堆大小大于大顶堆时,返回小顶堆的头部;
代码演示
// 小顶堆
private PriorityQueue<Integer> minHeap = new PriorityQueue<>();
// 大顶堆
private PriorityQueue<Integer> maxHeap = new PriorityQueue<>((o1,o2) ->o2 -o1);
// 记录当前次数 从0开始
private int count = 0;
public void Insert(Integer num) {
if (count % 2 == 0){
maxHeap.offer(num);
int max = maxHeap.poll();
minHeap.offer(max);
}else {
minHeap.offer(num);
int min = minHeap.poll();
maxHeap.offer(min);
}
count ++ ;
}
public Double GetMedian() {
if (minHeap.size() == maxHeap.size()){
return (double) (minHeap.peek() + maxHeap.peek()) / 2.0;
}else if (minHeap.size() < maxHeap.size()){
return maxHeap.peek() / 1.0;
}else{
return minHeap.peek() / 1.0;
}
}
京公网安备 11010502036488号