LeetCode 295. Find Median from Data Stream(multiset,heap)

題目

題意:有n個操作,存入數字,和輸出中位數

題解:要確保輸入數字的操作和輸出中位數的操作,都是低於等於Log(n)的效率。
那麼怎麼做呢?我們維護兩個multiset ,內部是一棵紅黑樹。一個樹A 維護的是較大值,樹B維護的是較小值。A,B平分秋色。
中位數顯然就是A裏的最小值和B裏的最大值中選擇。那麼在存數字的時候判斷這個數字應該放到哪個樹裏,然後再需要判斷A,B的元素數量差,如果出現差值大於1,就要把較多的那個樹的某個極值元素放到較小的那個樹裏,始終保持兩個樹的元素數量差不超過1,所以存入數字的效率是O(logn*3)
而取中位數是O(1)的效率
不知道爲什麼multiset的size()函數,會超時,難道是O(n)的效率取size嗎?介紹裏明明是constant的時間複雜度啊。
用優先隊列也可以的。效率是一樣的。

class MedianFinder {
public:
    /** initialize your data structure here. */
    multiset<int> m1;
    multiset<int> m2;
    int n=0;
    int len1;
    int len2;
    MedianFinder() {
        m1.clear();
        m2.clear();
        len1=0;
        len2=0;
        
    }
    
    void addNum(int num) {
       
        if(len1==0&&len2==0)
        {
            m1.insert(num);
            len1++;
            n++;
            return;
        }
       
        multiset<int>::iterator it = prev(m1.end());
        if(num < *it)
        {
            m1.insert(num);
            len1++;
        }
        else
        {
            m2.insert(num);
            len2++;
        }
        
        if(len1<len2-1)
        {
            m1.insert(*m2.begin());
            len1++;
            m2.erase(m2.begin());
            len2--;
        }
        
        if(len1-1>len2)
        {
            m2.insert(*prev(m1.end()));
            len2++;
            m1.erase(prev(m1.end()));
            len1--;
        }
        
        n++;
    }
    
    double findMedian() {
        
        if(n&1)
        {
            if(len1<len2)
                return *m2.begin();
            else
                return *prev(m1.end());
        }
        else
            return 1.0*(*prev(m1.end())+*m2.begin())/2;
        
    }
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder* obj = new MedianFinder();
 * obj->addNum(num);
 * double param_2 = obj->findMedian();
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章