题目:数据不断的进入,要求实现addNum()和findMedian()两个函数。来进行数字的添加和中位数的查找。
public void addNum(int num)
public double findMedian()
思路:1.先说一下基本的思路:
可以对目前的数据进行排序,如使用快速排序O(nlogn),然后直接返回中间的那个数O(1)。
2.
一:维护较大元素区间的minHeap和一个维护较小元素区间的maxHeap
二:怎么维持?用什么条件判断?(addNum的实现内容)
三:返回中位数时用什么条件判断?
用一个维护较大元素区间的minHeap和一个维护较小元素区间的maxHeap来做,时间复杂度为O(logn)(堆的操作时间复杂度为O(logn)),空间复杂度为O(n)。
为什么一个(维护较大元素)minHeap和一个(维护较小元素)maxHeap可以实现查找中位数?
因为维护较大元素的minHeap的堆顶元素和维护较小元素的maxHeap堆顶元素分别对应一个有序序列中间的2个数或1个数。就相当于用这两个不同的堆模拟了一个有序序列从中间分为两半。这两个堆的元素从一个方向看正好是一个有序序列。这样就可以获得中位数。
如何维持维护较大元素区间的minHeap和维护较小元素区间的maxHeap?
首先把一个元素加入maxHeap,然后经过堆调整后,把maxHeap堆顶元素加入到minHeap,这样就把大的元素(maxHeap出来的是最大值)慢慢地放到了minHeap中,就维持较大区间了。反过来也是,这样就可以维持。
注意:
1.其实第一下加到哪个heap都行
2.返回两堆顶的和/2.0,一定要/2.0化为double。size不相等时总体元素数为单数,返回minHeap堆顶元素。
3.用minHeap和maxHeap的size()来判断。
/*
先说一下有什么基本思路
思路:用两个堆,一个大顶堆,一个小顶堆。
大顶堆维护着较小的区间序列,小顶堆维护着较大的区间序列。
如果minHeap和maxHeap的总和是奇数,那么中位数就是minHeap的堆顶(第一步先往maxHeap放)
如果minHeap和maxHeap的总和是偶数,那么中位数就是minHeap和maxHeap各自堆顶的平均数。
怎么维护各自一直是较大或较小区间呢?
每加进堆一个元素,就把该堆的堆顶元素放到另一堆里,
这样就能保证较大的区间序列就一直是较大的,较小的区间序列就一直是较小的。
*/
PriorityQueue<Integer> minHeap = null;
PriorityQueue<Integer> maxHeap = null;
public MedianFinder() {
//优先队列PriorityQueue的底层是堆实现的,默认是最小堆
minHeap = new PriorityQueue<>();
//用lamda表达式来做,来构建最大堆
maxHeap = new PriorityQueue<>((x,y) -> (y-x));
}
public void addNum(int num) {
//先加入maxHeap,maxHeap为维护较小区间的大顶堆。应该也可以第一下先加minHeap
if(minHeap.size() == maxHeap.size()){
maxHeap.add(num);
minHeap.add(maxHeap.poll());
}else{
//加过maxHeap了,这次加minHeap
minHeap.add(num);
maxHeap.add(minHeap.poll());
}
}
public double findMedian() {
if(minHeap.isEmpty() && maxHeap.isEmpty()) return -999;
//返回值为double,所以要/2.0,化为浮点数
return minHeap.size() != maxHeap.size() ? minHeap.peek() : (minHeap.peek()+maxHeap.peek())/2.0;
}