LeetCode 295. Find Median from Data Stream (堆)

題目

求一個數組的中位數,但是這個數組是動態增加的,怎麼做呢?可以考慮到用插入排序,每增加一個值,都插入排序一下,最壞的效率是O(n),查詢效率是O(1)
效率太低,會超時。更高明的做法,是維護兩個堆,一個是大堆,一個是小堆,大堆的數字都大於小堆裏的數字,兩個堆的數字均分這個數字。大堆用最小堆實現,小堆用最大堆實現。
當插入一個數,我們把它跟大堆的堆頂,也就大數字裏的最小數對比,要是比它大,就入大堆,要是比它小,就入小堆,之後再調整兩個堆,保證平均,調整隻要比較堆頂的數字即可。

插入效率變成O(logn),查詢還是O(1)

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();
 */
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章