剑指offer63_数据流的中位数_题解
数据流的中位数
题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
分析
方案一:优先队列
将数据流分为几乎数量相同的两个部分,左边部分的数据比右边部分的数据小。
大顶堆 \(q1\) 保存左边部分的数据,小顶堆 \(q2\) 保存右边部分的数据
中位数可根据 \(A,B\) 的堆顶元素计算得到

- 为实现平均分配数据,当小顶堆 \(q2\) 的大小<=大顶堆 \(q1\) 的大小时,就将新数据添加到小顶堆 \(q2\) 中,否则添加到大顶堆 \(q1\) 中。这样可以保证小顶堆 \(q2\) 的大小始终>=大顶堆 \(q1\) 的大小
- 在插入新数据前检查左边部分(大顶堆)的数据是否都小于右边部分(小顶堆)的数据
- 如将新数据插入到小顶堆 \(q2\) 中时,需要检查新数据是否小于大顶堆 \(q1\) 的堆顶元素
- 如果小于则先将新数据插入到大顶堆 \(q1\) ,然后取出大顶堆 \(q1\) 的堆顶元素插入到小顶堆 \(q2\) ,并弹出大顶堆 \(q1\) 的对顶元素
- 如果大于则直接将新数据插入到小顶堆 \(q2\)
代码
/*
1.时间复杂度:O(logn)
堆的插入和弹出操作使用O(logn)时间
2.空间复杂度:O(1)
*/
class Solution {
public:
priority_queue<int> q1; //大顶堆
priority_queue<int, vector<int>, greater<int>> q2; //小顶堆
void Insert(int num) {
if (q2.size() <= q1.size())
{
if (!q1.empty() && num < q1.top())
{
q1.push(num);
q2.push(q1.top());
q1.pop();
}
else
{
q2.push(num);
}
}
else
{
if (!q2.empty() && q2.top() < num)
{
q2.push(num);
q1.push(q2.top());
q2.pop();
}
else
{
q1.push(num);
}
}
}
double GetMedian() {
int n = q1.size() + q2.size();
if (n % 2 == 0)
return (q1.top() + q2.top()) * 0.5;
else
return q2.top() * 1.0;
}
};

浙公网安备 33010602011771号