小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
题目
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值
例如,
[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();
*/