题目描述
有一个源源不断的吐出整数的数据流,假设你有足够的空间来保存吐出的数。请设计一个名叫MedianHolder的结构,MedianHolder可以随时取得之前吐出所有数的中位数。
[要求]
1. 如果MedianHolder已经保存了吐出的N个数,那么将一个新数加入到MedianHolder的过程,其时间复杂度是O(logN)。
2. 取得已经吐出的N个数整体的中位数的过程,时间复杂度为O(1)
每行有一个整数opt表示操作类型
若opt=1,则接下来有一个整数N表示将N加入到结构中。
若opt=2,则表示询问当前所有数的中位数
示例1
输入
[[1,5],[2],[1,3],[2],[1,6],[2],[1,7],[2]]
返回值
[5,4,5,5.5]
说明
第一次查询时结构内的数为:5
第二次查询时结构内的数为:3 5
第二次查询时结构内的数为:3 5 6
第二次查询时结构内的数为:3 5 6 7
示例2
输入
[[2],[1,1],[2]]
返回值
[-1,1]
【解析】
设计MedianHolder中两个堆,一个大根堆,一个小根堆。其中大根堆中接收所有数中较小的一半,这个堆中的堆顶就是较小那部分数中的最大值。小根堆则接收所有数中较大的一半,对顶则是较大一半数中的最小值。
具体流程如下:
1)第一个出现的数直接插入大根堆
2)以后每出现一个数num,判断num是否小于或者等于大根堆的堆顶。如果是,num进入大根堆;如果不是,num进入小根堆
3)每一个数加入完成后,判断大根堆和小根堆的大小。如果两个堆得个数相差超过1,从较多的那个堆中弹出堆顶,加入另一个堆。
class Solution {
public:
/**
* the medians
* @param operations int整型vector<vector<>> ops
* @return double浮点型vector
*/
vector<double> flowmedian(vector<vector<int> >& operations) {
// write code here
vector<double> res;
for(int i=0;i<operations.size();++i){
if(operations[i][0]==1){
insertNum(operations[i][1]);
}else{
res.push_back(getMedian());
}
}
return res;
}
void insertNum(int num){
int size = min_heap.size() + max_heap.size();
if(size%2==0){
if(max_heap.size()==0){
max_heap.push(num);
return;
}
if(num>min_heap.top()){
max_heap.push(min_heap.top());
min_heap.pop();
min_heap.push(num);
}else{
max_heap.push(num);
}
}else{
if(num<max_heap.top()){
min_heap.push(max_heap.top());
max_heap.pop();
max_heap.push(num);
}else{
min_heap.push(num);
}
}
}
double getMedian(){
int size = min_heap.size() + max_heap.size();
if(size ==0) return -1;
if(size%2 == 0)
return (max_heap.top() + min_heap.top())*0.5;
else
return max_heap.top();
}
private:
priority_queue<int, vector<int>, greater<int>> min_heap;//最小堆
priority_queue<int, vector<int>, less<int>> max_heap;//最大堆
};
class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int, vector<int>, greater<int>> Small;//小根堆
priority_queue<int, vector<int>, less<int>> Big;//大根堆
MedianFinder() {
}
void addNum(int num) {
//保证大顶堆的数据都小于小顶堆
//优先存入大根堆
if(Small.size()==Big.size()){
Small.emplace(num);
Big.emplace(Small.top());
Small.pop();
}else{
Big.emplace(num);
Small.emplace(Big.top());
Big.pop();
}
}
double findMedian() {
return Small.size()!=Big.size()?Big.top():(Small.top()+Big.top())/2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/