- 题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
- 输入
一串数据流,例如1,2,3,4,5,6,...。
- 输出
中位数
- 题目分析
感觉是简单的排序问题,不过涉及到动态数组保存输入数据,定个全局变量即可。
- 初步思路
List<Integer> arr = new ArrayList<>(); public void Insert(Integer num) { arr.add(num); } public Double GetMedian() { Collections.sort(arr); if (arr.size() % 2 == 0) { return (arr.get(arr.size()/2)*1.0 + arr.get(arr.size()/2-1)*1.0) / 2.0; } else { return arr.get((arr.size()-1)/2)*1.0; } }
- 堆
堆是一种树,由它实现的优先级队列的插入和删除的时间复杂度都是O(logn),用堆实现的优先级队列虽然和数组实现相比较删除慢了些,但插入的时间快的多了。当速度很重要且有很多插入操作时,可以选择堆来实现优先级队列。
因此定义一个小顶堆和大顶堆,较小的数放在大顶堆中,较大的数放在小顶堆中。
- 输入数据的个数为奇数时,小顶堆比大顶堆多一个数,因此小顶堆最上面的那个数据则为中位数。
- 输入数据的个数为偶数时,小顶堆与大顶堆大小相同,因此小顶堆最上面的那个数据和大顶堆最上面那个数据的平均值则为中位数。
PriorityQueue<Integer> left = new PriorityQueue<>(new Comparator<Integer>() { @Override //进行排序,小数在上 public int compare(Integer o1, Integer o2) { return o2-o1; } }); PriorityQueue<Integer> right = new PriorityQueue<>(); private int N; public void Insert(Integer num) { if(N%2==0){ left.add(num); right.add(left.poll()); }else{ right.add(num); left.add(right.poll()); } N++; } public Double GetMedian() { if(N%2==0) return (left.peek()+right.peek())/2.0; else return (double)right.peek(); }