
一开始只建立了一个优先队列,每次查询中位数时都要遍历一遍于是喜提时间超限,看了答案才恍然大悟原来还有这么聪明的办法。
方法是建立两个优先队列,一个大根堆一个小根堆,大根堆记录较小的数,小根堆记录较大的数。
每次加入元素时首先和大根堆最大的数进行比较,若元素更小则加入大根堆,否则加入小根堆,接着比较大根堆小根堆的大小,若大根堆比小根堆大超过一个元素(默认元素总数为奇数时大根堆多一个元素),则将大根堆最大元素加入小根堆并从大根堆移除那个元素;若小根堆比大根堆大时同理。
找出中位数时若总数为偶数(大根堆小根堆大小相等),则取大根堆最大元素和小根堆最小元素相加除以二;若总数为奇数(大根堆多一个元素),则直接取大根堆最大的元素。
好聪明的办法!!
另外小根堆构造方法是priority_queue<int,vector<int>,greater<int>> minq;,其中greater是小元素在前的比较函数。(大根堆中这个函数是less<int>)
cpp
class MedianFinder {
public:
priority_queue<int> maxq; //大根堆,记录较小的数
priority_queue<int,vector<int>,greater<int>> minq; //小根堆,记录较大的数
MedianFinder() {
}
void addNum(int num) {
if(maxq.empty()||num<maxq.top()){
maxq.emplace(num);
if(maxq.size()>minq.size()+1){
minq.emplace(maxq.top());
maxq.pop();
}
}
else{
minq.emplace(num);
if(minq.size()>maxq.size()){
maxq.emplace(minq.top());
minq.pop();
}
}
}
double findMedian() {
if(maxq.size()==minq.size()) return (maxq.top()+minq.top())/2.0;
else return maxq.top();
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/