牛客网刷题之数据流中的中位数

来源:互联网 发布:python 全文搜索引擎 编辑:程序博客网 时间:2024/06/08 11:34

题目描述:

这里写图片描述

解题思路:

  这种题属于在线算法类型的,有一个经典的问题就是在一亿个数中取出前100个最小数,显然,可以建立一个数量为100的最小堆来维护。类似的,我们这里也可以借鉴这种方法,但由于新增加的数可能会覆盖掉原先丢掉的数,所以我们还需要建立一个最大堆来进行维护。前面部分建立最大堆,后面部分建立最小堆。
  题目是求中位数,所以我们只需要位于中间的两个数就可以了,当元素个数为奇数个时可以看成这两个数一样。中位数在前半部分它是最大的,右半部分是最小的。我们只要始终知道前半部分数里的最大的那个数,后半部分里那个最小的数就可以了。为了实现平均分配,可以在数据的总数目是偶数时把新数据插入到最小堆中,否则插入最大堆中。
 另一个问题是保持最大堆的所有数据都小于最小堆中的数据。如果插入一个数使得总数目和为偶数,根据之前的原则应该插入最小堆中,但是新插入的元素可能比最大堆中的元素小怎么办?这就违反了最小堆的数据一定大于最大堆得原则。实际上这里插入的元素应该是新元素和最大堆中所有元素的最大值,最大堆正好有返回一个最大值的作用,所以新插入的元素先插入最大堆,然后取出最大值再插入最小堆中。如果插入元素使得数据总数目和为奇数,处理方法类似。
 这里还需要注意的是PriorityQueue默认是小顶堆,实现大顶堆,需要反转默认排序器。

题解:

    private int count = 0;    private PriorityQueue<Integer> minHeap = new PriorityQueue<>();    private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {        @Override        public int compare(Integer o1, Integer o2) {            return o2 - o1;        }    });    public void Insert(Integer num) {        if ((count & 1) == 0) {            maxHeap.offer(num);            int maxNumInmaxHeap = maxHeap.poll();            minHeap.offer(maxNumInmaxHeap);            }else{            minHeap.offer(num);            int minNumInminHeap = minHeap.poll();            maxHeap.offer(minNumInminHeap);        }        count++;    }    public Double GetMedian() {        if ((count & 1) == 0) {            return new Double((minHeap.peek() + maxHeap.peek())) / 2;        } else {            return new Double(minHeap.peek());        }    }

ac结果:

这里写图片描述

0 0