數據流中的中位數

在牛客上看到這樣一道題:

題目描述

如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。


解題思路:

可能看到這道題的第一反應是,這沒什麼難度呀,題目都說了用排序了,時間複雜度nlogn,如果這麼簡單的話,這題就沒什麼必要出了。

對於這種找出很大數據中的前幾個數,或者個別數的情況,最經典的解法就是用堆。

我們可以用一個最大堆來維護當前前n/2小的元素,而且數據要動態增長,有可能之前被替換掉的元素隨着元素的增加又跑回來了,所以我們不能直接把元素丟掉,而是應該用一個最小堆來存前n/2大的元素。


下面貼上代碼:

class Solution {
    private:
        vector<int> min; //數組中的後一半元素組成一個最小化堆
        vector<int> max; //數組中的前一半元素組成一個最大化堆
    public:
        void Insert(int num) {
            if(((min.size()+max.size()) & 1) == 0) {  //偶數數據的情況下,則在最小堆中插入元素
                if(max.size() > 0 && num < max[0]) {
                    max.push_back(num);
                    push_heap(max.begin(), max.end(), less<int>());
                    num=max[0];
                    pop_heap(max.begin(), max.end(), less<int>());
                    max.pop_back();
                }
                min.push_back(num); //把前一半找到的最大值放到後一半中
                push_heap(min.begin(), min.end(), greater<int>());
            } else {
                if(min.size() > 0 && num > min[0]) {   //奇數數據的情況下,則在最大堆中插入元素
                    min.push_back(num);
                    push_heap(min.begin(), min.end(), greater<int>());
                    num=min[0];
                    pop_heap(min.begin(), min.end(), greater<int>());
                    min.pop_back(); 
                }
                max.push_back(num); //把後一半找到的最大值放到前一半中
                push_heap(max.begin(), max.end(), less<int>());
            }
        }

        double GetMedian() { 
            int size=min.size() + max.size();
            if(size==0) return -1;
            if((size&1) != 0) {
                return (double) min[0];
            } else {
                return (double) (max[0] + min[0]) / 2;
            }
        }
};





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章