題目描述
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。我們使用Insert()方法讀取數據流,使用GetMedian()方法獲取當前讀取數據的中位數。
有下面兩種思路:
1. 使用一個數組保存數據流中的數據,每次insert時,使用插入排序,保證數組中的數據是從小到大排序的
2. 使用一個大頂堆和一個小頂堆保存數據,每次insert時,使大頂堆的元素都小於小頂堆的元素,並且兩個堆的大小不超過2,這樣,中位數就在兩個堆頂之中,這種思路其實類似於平衡二叉樹
代碼如下:
class Solution {
public:
//方法一: 使用數組保存數據流,每次插入時,從小到大排序
vector<int> array;
void insert_array(int num){
array.push_back(num);
for(int i = array.size()-1; i > 0; i--){
if(array[i] < array[i-1]){
array[i] ^= array[i-1];
array[i-1] ^= array[i];
array[i] ^= array[i-1];
}
else{
break;
}
}
}
double get_array_median(){
int size = array.size();
if(size % 2 == 1){
return array[size / 2];
}
else{
return (array[size / 2] + array[size / 2 - 1]) / 2.0;
}
}
//方法二:使用一個大頂堆和一個小頂堆保存數據
//保證大頂堆的數,都小於小頂堆的數, 則滿足排序要求
//每次你新來的數 先判斷可以放到哪一個堆中
//保證兩個堆的個數的差,不大於1,則平均值就在兩個堆頂之中
priority_queue<int, vector<int>, less<int> > p; //大頂堆
priority_queue<int, vector<int>, greater<int> > q; //小頂堆
void insert_heap(int num){
if(p.empty() || num < p.top()){
p.push(num);
}
else{
q.push(num);
}
if(p.size() == q.size() + 2){
q.push(p.top());
p.pop();
}
if(p.size() == q.size() - 2){
p.push(q.top());
q.pop();
}
}
double get_heap_median(){
if(p.size() == q.size()){ //兩個堆元素個數相同,則結果是堆頂的平均值
return (p.top() + q.top()) / 2.0;
}
else{
return p.size() > q.size() ? p.top() : q.top(); //哪個堆個數大,則結果就是哪個堆的堆頂
}
}
void Insert(int num){
//insert_array(num);
insert_heap(num);
}
double GetMedian() {
//return get_array_median();
return get_heap_median();
}
};