方法1:暴力
我们使用一个vector来存数组
并且对于每次中位数的计算,我们直接排序一遍,然后寻找中位数即可
时间复杂度:插入数字O(1),查找中位数O(nlogn)
空间复杂度:O(n)

class Solution {
public:
    vector<int> v;//用于存数组
    void Insert(int num) {
        v.push_back(num);
    }
    double GetMedian() { 
        sort(v.begin(), v.end());
        int sz = v.size();
        if (sz & 1) return v[sz / 2];//如果是奇数个,则是中间的那个
        else return (v[sz / 2] + v[sz / 2 - 1]) / 2.0;//否则就是中间的两个取平均值
    }
};

方法2:对顶堆
这个是利用了STL中的priority_queue可以取最值的特性来做动态取中位数的题目
我们创建两个堆,一个用大顶堆,一个用小顶堆
我们要保证
序列中前个元素在大根堆中,剩余的都在小根堆中
当一共有奇数个元素时,中位数是小根堆顶
当一共有偶数个元素时,中位数是大根堆顶
过程是这样的
第一个元素放到小根堆中
接下来插入的元素,当该元素大于当前中位数,就插入到小根堆顶,否则插入到大根堆顶
如果大根堆的元素个数大于小根堆的元素个数,就让大根堆顶弹出到小根堆中
如果小根堆的元素个数-大根堆的元素个数 > 1,就让小根堆顶弹出到大根堆中
接下来给大家模拟一下
我们依次将[5、2、3、4、1、6、7]插入序列中
首先是第一个元素,我们插入小根堆
图片说明
然后是第二个元素,我们发现比当前中位数少,于是插入到大根堆中
因为是偶数个元素,于是中位数大根堆堆顶和小根堆堆顶的平均数
图片说明
第三个元素,我们发现比当前中位数少,于是插入到大根堆中
此时,大根堆元素比小根堆多,于是将大根堆堆顶弹出到小根堆中
图片说明
第四个元素,我们发现比当前中位数大,于是插入到小根堆中
此时,小根堆元素比大根堆多,于是将小根堆堆顶弹出到大根堆中
图片说明
接下来依次类推
图片说明
图片说明
图片说明
时间复杂度:插入数字O(logn),求中位数O(logn)
空间复杂度:O(n)

class Solution {
public:
    priority_queue<int> q1;//大根堆
    priority_queue<int, vector<int>, greater<>> q2;//小根堆
    double now;//当前中位数
    int cnt = 0;//当前插入的元素个数
    void Insert(int num) {
        cnt ++ ;
        if (q2.empty()) q2.push(num);//插入第一个元素
        else {
            //选择插入的堆
            if (num < now) q1.push(num);
            else q2.push(num);
        }
        //插入之后调整堆
        if (q1.size() > q2.size()) {
            q2.push(q1.top());
            q1.pop();
        } else if (q2.size() - q1.size() > 1) {
            q1.push(q2.top());
            q2.pop();
        }
    }
    double GetMedian() { 
        //记得更新now
        if (cnt & 1) now = q2.top();
        else now = (q2.top() + q1.top()) / 2.0;
        return now;
    }
};