题目
如何得到一个数据流中的中位数?
如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
数据范围:数据流中数个数满足 ,大小满足
进阶: 空间复杂度 , 时间复杂度
示例1
输入:[5,2,3,4,1,6,7,0,8] 返回值:“5.00 3.50 3.00 3.50 3.00 3.50 4.00 3.50 4.00 “ 说明:数据流里面不断吐出的是5,2,3…,则得到的平均数分别为5,(5+2)/2,3…
解题思路:优先队列 / 堆
建立一个 大顶堆 和 小顶堆
,各保存列表的一半元素,且规定:
保存 较小 的一半,长度为
(
为偶数)或
(
为奇数)
保存 较大 的一半,长度为
(
为偶数)或
(
为奇数)
随后,中位数可仅根据 和
的堆顶元素计算得到。

添加算法流程:设总数
当
(即
为 偶数):需向
添加一个元素。
实现方法:将新元素
num插入至,再将
堆顶元素插入至
;
当
(即
为 奇数):需向
添加一个元素。
实现方法:将新元素
num插入至,再将
堆顶元素插入至
;
查找算法流程:设总数
- 当
(即
为 偶数):则中位数为 (
的堆顶元素 +
的堆顶元素 )/2。
- 当
(即
为 奇数):则中位数为
的堆顶元素
复杂度分析
时间复杂度: ,其中
是数组长度。
- 查找中位数 :获取堆顶元素使用 时间;- 添加数字  : 堆的插入和弹出操作使用  时间。
空间复杂度: : 其中
为数据流中的元素数量
官方代码
class MedianFinder {Queue<Integer> A, B;public MedianFinder() {A = new PriorityQueue<>((o1, o2) -> {o2 - o1}); // 大顶堆,保存较小的一半B = new PriorityQueue<>(); // 小顶堆,保存较大的一半}public void addNum(int num) {// 奇数,向B加if(A.size() != B.size()) {A.add(num);B.add(A.poll());} else { // 偶数,向A加B.add(num);A.add(B.poll());}}public double findMedian() {return A.size() != B.size() ? A.peek() : (A.peek() + B.peek()) / 2.0;}}
我的代码
public class Solution {// A 存数字小的区域的大根堆PriorityQueue<Integer> ASmallMax=new PriorityQueue<>((o1,o2)->{return o2-o1;});// B 存数字大的区域的小根堆PriorityQueue<Integer> BBigMin=new PriorityQueue<>((o1,o2)->{return o1-o2;});public void Insert(Integer num) {// 奇数,向B中添加if(ASmallMax.size()>BBigMin.size()){ASmallMax.add(num);BBigMin.add(ASmallMax.poll());}else{ // 偶数,向A中添加BBigMin.add(num);ASmallMax.add(BBigMin.poll());}return ;}public Double GetMedian() {// 奇数if(ASmallMax.size()>BBigMin.size()){return (double)ASmallMax.peek();}else{return (ASmallMax.peek()+BBigMin.peek())/2.0;}}}
