题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
思路1:插入排序
时间复杂度为O(n2 )
class Solution {
private:
vector<int> data;
public:
void Insert(int num)
{
if(data.empty() || num > data[data.size()-1])
data.push_back(num);
else{
for(int i = 0;i < data.size();i++){
if(num <= data[i]){
data.insert(data.begin()+i,num);
break;
}
}
}
}
double GetMedian()
{
double res;
int len = data.size();
if(len % 2 == 1){//odd
res = (double)data[len / 2];
}else{
res = (double)(data[len / 2] + data[len / 2 - 1]) / 2;
}
return res;
}
};
思路2:借用堆排序
时间复杂度O(logn)
把输入的数据流一分为二
左半部分存在大顶堆left里
右半部分存在小顶堆right里
要求大顶堆的堆顶永远 小于 小顶堆的堆顶
并且大顶堆和小顶堆的元素个数必须 相等 或者 大顶堆比小顶堆多一个
(因为要求中位数,left和right的堆顶必须能得出中位数)
具体实现思路就是先判断当前数字放进left还是right,然后再调整left和right的大小关系
class Solution {
private:
priority_queue<int> left;//左半部分大顶堆
priority_queue<int,vector<int>,greater<int> > right;//右半部分小顶堆
public:
void Insert(int num)
{
if(left.empty() || num < left.top())
left.push(num);
else
right.push(num);
if(right.size() - left.size() == 1){
left.push(right.top());
right.pop();
}
if(left.size() - right.size() == 2){
right.push(left.top());
left.pop();
}
}
double GetMedian()
{
double res;
if(left.size() > right.size())
res = (double)left.top();
else
res = (double)(left.top() + right.top()) / 2;
return res;
}
};