剑指offer63_数据流的中位数_题解

数据流的中位数

题目描述

如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

分析

方案一:优先队列

将数据流分为几乎数量相同的两个部分,左边部分的数据比右边部分的数据小。

大顶堆 \(q1\) 保存左边部分的数据,小顶堆 \(q2\) 保存右边部分的数据

中位数可根据 \(A,B\) 的堆顶元素计算得到

Picture1.png

  1. 为实现平均分配数据,当小顶堆 \(q2\) 的大小<=大顶堆 \(q1\) 的大小时,就将新数据添加到小顶堆 \(q2\) 中,否则添加到大顶堆 \(q1\) 中。这样可以保证小顶堆 \(q2\) 的大小始终>=大顶堆 \(q1\) 的大小
  2. 在插入新数据前检查左边部分(大顶堆)的数据是否都小于右边部分(小顶堆)的数据
  3. 如将新数据插入到小顶堆 \(q2\) 中时,需要检查新数据是否小于大顶堆 \(q1\) 的堆顶元素
    1. 如果小于则先将新数据插入到大顶堆 \(q1\) ,然后取出大顶堆 \(q1\) 的堆顶元素插入到小顶堆 \(q2\) ,并弹出大顶堆 \(q1\) 的对顶元素
    2. 如果大于则直接将新数据插入到小顶堆 \(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;
    }
};
posted @ 2021-02-28 20:31  RiverCold  阅读(60)  评论(0)    收藏  举报