我記得以前做題就經常碰到堆,但是也沒有記錄過什麼,今天決定記錄一下堆的應用!
1.找中位數
295. 數據流的中位數
中位數是有序列表中間的數。如果列表長度是偶數,中位數則是中間兩個數的平均值。
例如,
[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
這道題就是所謂的添加元素,然後找中位數,這題我開始用的是List 加 lower_bound()結果後來超時,後來看了題解用堆確實是好方法!!!
1.你需要維護兩個堆:
priority_queue<int,vector,less> low; (大頂堆)
priority_queue<int,vector,greater> up;(小頂堆)
一個堆用來存放一半小數字(low),一半大數字(up).
如圖(紅色是low堆的值,藍色應該是up堆的值)
之後變成堆的結構應該如下圖:
其實很容易看出來,如果爲單數,取的就是大頂堆(low)的頂,若爲偶數,就取大頂堆和小頂堆頂和除2!
2.關於添加數字。如何添加,若添加的數字num大於up頂的值,很明顯,應該添加到up裏面,其他情況添加到low裏面。之後保證low中的值永遠大於up的值+1或者數量相等,適當的把兩者的top值移動,保持上述條件即可。
代碼如下
class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int,vector<int>,less<int>> low;
priority_queue<int,vector<int>,greater<int>> up;
MedianFinder() {
}
void addNum(int num) {
if(!up.empty()&&num > up.top()) up.push(num);
else low.push(num);
if(low.size() > up.size()+1){
up.push(low.top());
low.pop();
}
if(low.size() < up.size()){
low.push(up.top());
up.pop();
}
}
double findMedian() {
if(low.size() > up.size()) return double(low.top());
else return double(low.top()+up.top())/2;
}
};
(圖片借用了Leecode)
未完待續…