1. 程式人生 > >資料流中的中位數(劍指offer/C++)

資料流中的中位數(劍指offer/C++)

題目描述

如何得到一個數據流中的中位數?如果從資料流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從資料流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取資料流,使用GetMedian()方法獲取當前讀取資料的中位數。

室友大晚上回來和我分享這道題解題思路,他給出的方案是藉助最大堆和最小堆資料結構解題,這一塊我應用不是很熟,我首先想到的就是用map容器對資料流中的數值進行計數,再用利用一個計數器找出中位數。

這裡需要提一下是map的底層實現是紅黑樹(插入資料時,已經自動完成排序(基於key)),保證了一個穩定的動態操作時間,查詢、插入、刪除都是O(logN),最壞和平均都是。但是在利用計數器查詢的時候,時間複雜度是O(N)。演算法細節見程式碼:

class Solution {
public:
    map<int, int> mp;
    int count = 0;
    void Insert(int num)
    {
        count++;
        if (mp.find(num) == mp.end())
        {
            mp[num] = 1;
        }
        else
        {
            mp[num]++;
        }
    }
    double GetMedian()
    { 
        if (count % 2 != 0)
        {
            int tmp = 0;
            map<int, int>::iterator it = mp.begin();
            while (it != mp.end())
            {
                tmp += it->second;
                if (tmp > count / 2)
                {
                    return 1.0*it->first;
                }
                it++;
            }
        }
        else
        {
            int tmp = 0;
            map<int, int>::iterator it = mp.begin();
            while (it != mp.end())
            {
                tmp += it->second;
                if (tmp > (count - 1) / 2 )
                {
                    if (tmp > count / 2)
                    {
                        return 1.0*it->first;
                    }
                    else
                    {
                        return 1.0*(it->first + (++it)->first)/2.0;
                    }
                }
                it++;
            }
        }
        return 0;
    }
};