【重温经典】数据流的中位数
方法1:大小根堆
- 维护maxHeap 和minHeap,保持maxHeap.size() = minHeap.size() 或者maxHeap.size() = minHeap.size()+1
- maxHeap维护的数据属于整个数据流的下半部分的数据,minHeap维护的数据属于整个数据流上半部分的数据
- 返回中位数的时候,注意总体的数据个数的奇偶性
class MedianFinder {
//大根堆,从栈顶到栈底 依次从大到小
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(((o1, o2) -> o2 - o1));
//小根堆,从栈顶到栈底 依次从小到大
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
int cnt = 0;
/**
* initialize your data structure here.
*/
public MedianFinder() {
}
public void addNum(int num) {
cnt++;
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
if (cnt % 2 == 1) maxHeap.offer(minHeap.poll());
}
public double findMedian() {
if(cnt %2 ==1 ){
return maxHeap.peek();
}else {
return (maxHeap.peek()+minHeap.peek())/2.0;
}
}
}
方法2:大小根堆(不使用计数器)
- 不使用计数器,用queue的size进行判断
class MedianFinder {
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>((o1, o2) -> o2 - o1);
PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
public MedianFinder() {
}
public void addNum(int num) {
maxHeap.offer(num);
minHeap.offer(maxHeap.poll());
if (maxHeap.size() < minHeap.size()) maxHeap.offer(minHeap.poll());
}
public double findMedian() {
if (maxHeap.size() == minHeap.size())
return (maxHeap.peek() + minHeap.peek()) / 2.0;
else
return maxHeap.peek();
}
}
FollowUp
Q:如果数据流中所有整数都在 0 到 100 范围内,你将如何优化你的算法?
A:存储一个100范围的arr数组,记录0-100数据出现的个数,以及总的数据的个数,遍历arr数组,可以计算出中位数
Q:如果数据流中 99% 的整数都在 0 到 100 范围内,你将如何优化你的算法?
A:如上还是维持以上的一个arr数组,对于<0和>100的数据,统计个数,这部分数据对结果不会产生影响,因为中位数出现在99%的数据里面,即0-100这个范围内