在牛客上看到這樣一道題:
題目描述
如何得到一個數據流中的中位數?如果從數據流中讀出奇數個數值,那麼中位數就是所有數值排序之後位於中間的數值。如果從數據流中讀出偶數個數值,那麼中位數就是所有數值排序之後中間兩個數的平均值。
解題思路:
可能看到這道題的第一反應是,這沒什麼難度呀,題目都說了用排序了,時間複雜度nlogn,如果這麼簡單的話,這題就沒什麼必要出了。
對於這種找出很大數據中的前幾個數,或者個別數的情況,最經典的解法就是用堆。
我們可以用一個最大堆來維護當前前n/2小的元素,而且數據要動態增長,有可能之前被替換掉的元素隨着元素的增加又跑回來了,所以我們不能直接把元素丟掉,而是應該用一個最小堆來存前n/2大的元素。
下面貼上代碼:
class Solution {
private:
vector<int> min; //數組中的後一半元素組成一個最小化堆
vector<int> max; //數組中的前一半元素組成一個最大化堆
public:
void Insert(int num) {
if(((min.size()+max.size()) & 1) == 0) { //偶數數據的情況下,則在最小堆中插入元素
if(max.size() > 0 && num < max[0]) {
max.push_back(num);
push_heap(max.begin(), max.end(), less<int>());
num=max[0];
pop_heap(max.begin(), max.end(), less<int>());
max.pop_back();
}
min.push_back(num); //把前一半找到的最大值放到後一半中
push_heap(min.begin(), min.end(), greater<int>());
} else {
if(min.size() > 0 && num > min[0]) { //奇數數據的情況下,則在最大堆中插入元素
min.push_back(num);
push_heap(min.begin(), min.end(), greater<int>());
num=min[0];
pop_heap(min.begin(), min.end(), greater<int>());
min.pop_back();
}
max.push_back(num); //把後一半找到的最大值放到前一半中
push_heap(max.begin(), max.end(), less<int>());
}
}
double GetMedian() {
int size=min.size() + max.size();
if(size==0) return -1;
if((size&1) != 0) {
return (double) min[0];
} else {
return (double) (max[0] + min[0]) / 2;
}
}
};