【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(); */