剑指 Offer 41. 数据流中的中位数 - 力扣(Leetcode)
分析
维护两个堆,一个大根堆,一个小根堆。
- 插入操作:
当进行插入时,先判断大根堆中是否有元素,如果没有直接插入大根堆,若有元素,将当前插入值与大根堆中的堆顶元素比较,如果当前值较小,那么直接插入大根堆。若当前值大于等于堆顶元素,则将其插入小根堆。- 查询操作:
查询时,我们需要保证大根堆与小根堆的元素个数相等或相差一。因为只有这样,堆顶元素才是中位数。因此我们先循环判断大根堆中的元素个数与小根堆中元素个数之差是否大于1。若大于一,则取出大根堆顶的元素,插入小根堆。然后循环判断小根堆元素个数是否大于大根堆,若大于,则取出插入大根堆。当完成这两个循环后,大根堆的元素个数应该是与小根堆相等或大一。若大一,则直接返回大根堆顶元素,否则返回大根堆顶元素和小根堆顶元素的平均数。
代码
优先队列
class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int> q1;
priority_queue<int,vector<int>, greater<int> > q2;
MedianFinder() {
}
void addNum(int num) {
if (q1.size()==0)
{
q1.push(num);
return;
}
if (num>q1.top())
q2.push(num);
else
q1.push(num);
return;
}
double findMedian() {
while (q1.size()>q2.size()+1)
{
int k=q1.top();
q1.pop();
q2.push(k);
}
while (q2.size()>q1.size())
{
int k=q2.top();
q2.pop();
q1.push(k);
}
if (q1.size()==q2.size())
{
return (q1.top()+q2.top())/2.0;
}
else
return q1.top();
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/