【设计】——数据流中的中位数

144 阅读1分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

题目

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值

例如,

[2,3,4] 的中位数是 3

[2,3] 的中位数是 (2 + 3) / 2 = 2.5

设计一个支持以下两种操作的数据结构:

void addNum(int num) - 从数据流中添加一个整数到数据结构中。 double findMedian() - 返回目前所有元素的中位数。

来源:力扣(LeetCode)

难度:hard

思路

1.将数据平均分成两部分,创建一个小根堆存储较大部分的数据,一个大根堆存储较小部分的数据

    PriorityQueue<Integer> big = new PriorityQueue<>(); //存储较小部分的元素
    PriorityQueue<Integer> small = new PriorityQueue<>((a, b) -> (b - a)); //存储较大部分的元素

2.小根堆中的数据个数等于大根堆或者比大根堆多1

3.每次添加时根据大根堆和小根堆中的数据量来进行添加,如果big.size()==small.size(),那么这次add要让小根堆的数量+1,那么这个num是要先加到大根堆中的,从大根堆中弹出最大的元素加到小根堆中(这样才能保证小根堆中的数都大于或者等于大根堆中最大的数)。如果big.size()<small.size(),同理。

代码

class MedianFinder {

    /**
     * initialize your data structure here.
     */
    PriorityQueue<Integer> big = new PriorityQueue<>(); //存储较小部分的元素
    PriorityQueue<Integer> small = new PriorityQueue<>((a, b) -> (b - a)); //存储较大部分的元素

    public MedianFinder() {

    }

    public void addNum(int num) {
        if (small.size() == big.size()) {
            big.add(num);
            small.add(big.poll());
        } else {
            small.add(num);
            big.add(small.poll());
        }
    }

    public double findMedian() {
        if (small.size() == big.size()) {
            return (1.0 * small.peek() + big.peek()) / 2;
        }
        return 1.0 * small.peek();
    }
}

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */