劍指offer——資料流中的中位數C++(堆-優先佇列)
阿新 • • 發佈:2021-01-07
技術標籤:劍指Offer#佇列演算法資料結構優先佇列堆劍指offer
vector加sort不香嗎,時間複雜度O(nlogn),實際執行比這個更快誒。雖香但滾。
因為是中位數,所以把左右分成兩塊,左邊是大頂堆,右邊是小頂堆。堆的插入時間複雜度為O(lgn),取值的時間複雜度就是O(1),因為就是取兩個堆頂的操作。插入滿足兩個操作:1.兩邊的資料量之差不大於1,2.且左邊全小於右邊。
所以我們的插入操作是,當前資料總量是偶數時,將其插入左堆(過程是先插入右,再將右的堆頂插入到左堆),奇數時反向操作。這樣子就可以保證左堆>=右堆,且左邊一定小於右邊。取值時當前為奇數,就去左堆堆頂取,為偶數時,就取兩個堆頂/2,記得都轉為double
class Solution {
public:
//法1,用一個vector每次插入後排序,然後插入後排序
//法2:左邊一個大頂堆,右邊一個小頂堆
//最小堆的插入時間複雜度是O(lgn),取值是O(1),因為就是取兩個堆頂的值即可
//最主要是插入時要保證兩點,兩邊的資料量不大於1,且左邊全部小於右邊
//當前資料量是偶數時,先將值插入右邊(小頂堆),然後彈出堆頂元素插入大頂堆
//當前資料量是奇數時,先將值插入左邊(大頂堆),然後彈出堆頂元素插入小頂堆
//此時一定能保證以上兩點全部滿足
//取中位數時,當前資料量為奇數時,取大頂堆首部,如果是偶數,就取兩個堆頂平均值
void Insert(int num)
{
if((left.size() + right.size()) % 2 == 0){
right.push(num);
//可以erase(right.begin())或者right.pop即可
left.push(right.top());
right.pop();
}
else{
left.push(num);
right.push(left. top());
left.pop();
}
}
double GetMedian()
{
if((left.size()+right.size())%2 ==1){
return double(left.top());
}
else return double(left.top()+right.top())/2;
}
private:
//less是從大到小(大頂堆),greater是從小到大(小頂堆)
//left是大頂堆左邊的
priority_queue<int,vector<int>,less<int>> left;
priority_queue<int,vector<int>,greater<int>> right;
};