中位数就是所有数值排序!!!之后位于中间的数值
既然要对所有元素进行排序,考虑使用自带排序的容器:然后TreeSet和TreeMap都不适合
那考虑使用堆来做
思想:
建立两个堆,一个大顶堆lowHeap,一个小顶堆 highHeap
其中大顶堆lowHeap用于存储已加入数字中较小的那一部分数字(这样堆顶的数字即为那一半较小数字中的最大值)
小顶堆highHeap用于存储已加入数字中较大的那一部分数字(这样堆顶的数字即为那一半较大数字中的最小值)
这样做方便最终求中位数:
case1:若两堆中的数一样多则表明数的总量位偶数,则中位数即为对两个堆的堆顶元素求平均即可
case2:若两堆中的数不一样多,如果我们让小顶堆中的数的个数保持要么始找等于大顶堆中数的个数(对应case1)要么比其多1个的话那么此时中位数即为小顶堆的堆顶元素
所以接下来重点是如何往这两个堆中插入元素还能保持两个堆中元素的数量始终满足条件1:在插入过程中只要始终报错保持小顶堆中元素的个数始终比大顶堆中数的个数最多多1个
可以这么做:
先把数字往大顶堆中插入(先往小区间插),然后如果发现此时小顶堆中的元素个数不满足条件1
那么我们就可以把堆顶元素(最大的那个)插入到小顶堆中(用于存储较大那部分数的那个堆),然后此时又有可能破坏条件1,即小顶堆中元素的个数有可能比大顶堆中元素的个数多1个以上,那我就把小顶堆的堆顶元素(较大那部分数中最小的那个给淘汰掉)把其放回到大顶堆中,这样就有可能使条件1成立))
一直重复上述步骤直到所有数都被插入完成
class MedianFinder {PriorityQueue<Integer> smallHeap;PriorityQueue<Integer> bigHeap;/** initialize your data structure here. */public MedianFinder() {smallHeap = new PriorityQueue<>();bigHeap = new PriorityQueue<>((o1,o2)->o2-o1);}public void addNum(int num) {bigHeap.add(num);if(bigHeap.size()>=smallHeap.size()){smallHeap.add(bigHeap.poll());if(smallHeap.size()>bigHeap.size()+1){bigHeap.add(smallHeap.poll());}}}public double findMedian() {if(bigHeap.size()==smallHeap.size()){return (bigHeap.peek()+smallHeap.peek())/2.0;}return smallHeap.peek();}
}/*** Your MedianFinder object will be instantiated and called as such:* MedianFinder obj = new MedianFinder();* obj.addNum(num);* double param_2 = obj.findMedian();*/