1. 程式人生 > >【LeetCode】295. 資料流的中位數 結題報告 (C++)

【LeetCode】295. 資料流的中位數 結題報告 (C++)

原題地址:https://leetcode-cn.com/problems/find-median-from-data-stream/

題目描述:

中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。

例如,

[2,3,4] 的中位數是 3

[2,3] 的中位數是 (2 + 3) / 2 = 2.5

設計一個支援以下兩種操作的資料結構:

void addNum(int num) - 從資料流中新增一個整數到資料結構中。
double findMedian() - 返回目前所有元素的中位數。
示例:

addNum(1)
addNum(2)
findMedian() -> 1.5
addNum(3) 
findMedian() -> 2
進階:

如果資料流中所有整數都在 0 到 100 範圍內,你將如何優化你的演算法?
如果資料流中 99% 的整數都在 0 到 100 範圍內,你將如何優化你的演算法?

 

解題方案:

設計題型。這裡使用了C++STL中的upper_bound()函式。

upper_bound(a.begin(),a.end(),x)返回的是迭代器,upper_bound(a+i,a+j,x)-a返回的是第一個大於x的數的座標。

在這裡算是在指定位置插入元素。upper_bound()和insert()函式組合使用。

程式碼:

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        auto it = upper_bound(nums.begin(), nums.end(), num);
        nums.insert(it, num);
    }
    
    double findMedian() {
        int n = nums.size();
        if(n % 2 == 0) 
            return 1.0 * (nums[n / 2 - 1] + nums[n / 2]) / 2;
        else 
            return nums[n / 2];
    }
    vector<int> nums;
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */

不需要所有的資料有序,只需要中間的值,很自然想到把列表分成兩半,分別用兩個資料結構來儲存,比如[1,3,4,5,6,7],對於這個列表,可以存為[1,3,4]和[5,6,7],那麼只需要中間的值就可以得出中位數了。

可以採用優先順序佇列,priority_queue:左側為數字越大優先順序越高,右側為數字越小優先順序越高。那麼取出兩個優先順序的top值即可。 

程式碼:

class MedianFinder {
public:
    /** initialize your data structure here. */
    MedianFinder() {
        
    }
    
    void addNum(int num) {
        left.push(num);
        if(left.size() - right.size() > 1) {
            right.push(left.top());
            left.pop();
        }
        if(right.size() > 0 && left.top() > right.top()){
            int tmp = left.top();
            left.pop();
            left.push(right.top());
            right.pop();
            right.push(tmp);
        }
    }
    
    double findMedian() {
        if(left.size() == right.size()) 
            return 1.0 * (left.top() + right.top()) / 2;
        else 
            return left.top();
    }
    priority_queue<int, vector<int>,greater<int>> right;
    priority_queue<int, vector<int>,less<int>> left;
};

/**
 * Your MedianFinder object will be instantiated and called as such:
 * MedianFinder obj = new MedianFinder();
 * obj.addNum(num);
 * double param_2 = obj.findMedian();
 */