目录
题目
题目出处:https://leetcode-cn.com/problems/find-median-from-data-stream/
思路:在数据插入的过程中维护一个大根堆和一个小根堆,并始终保持大根堆的元素个数==小根堆的个数或者大根堆的元素个数==小根堆的个数-1。大根堆中存放的是数据流的较小半段元素;小根堆中存放的是数据流中的较大一半的元素。每次数据插入都针对小根堆。
流程:
- 若小根堆为空则将该元素直接插入小根堆。
- 若小根堆堆顶的元素大于当前要插入的元素,则将该元素插入到大根堆中,并判断此时大根堆和小根堆的元素个数的大小,若大根堆的元素个数多于小根堆的元素个数,则将此时大根堆的堆顶元素弹出并插入到小根堆中。
- 若小根堆堆顶的元素小于等于当前要插入的元素,则将该元素插入到小根堆中,并判断此时大根堆和小根堆的元素个数的大小,若小根堆中的元素个数比大根堆中元素个数多2个及以上,则将小根堆堆顶元素弹出并插入到大根堆中去。
class MedianFinder {
private:
int n = 0;
priority_queue<int, vector<int>, greater<int>> small_q; //小根堆,升序
priority_queue<int, vector<int>, less<int>> big_q; //大根堆,降序
public:
/** initialize your data structure here. */
MedianFinder() {
}
void addNum(int num) {
if(small_q.empty()){ //小根堆为空,直接插入
small_q.push(num);
}
else if(num > small_q.top()){ //插入元素比小根堆堆顶元素大,直接插入
small_q.push(num);
if(small_q.size() > big_q.size()+1){
big_q.push(small_q.top());
small_q.pop();
}
}
else{ //插入的元素比比小根堆堆顶元素小, 往大根堆中插入
big_q.push(num);
if(small_q.size() < big_q.size()){
small_q.push(big_q.top());
big_q.pop();
}
}
++n;
}
double findMedian() {
if(n & 1){
return small_q.top();
}
return (small_q.top()+big_q.top()) / 2.0;
}
};
基础知识补充
优先队列
priority_queue<int, vector<int>, greater<int>> q; //升序排序,小根堆
priority_queue<int, vector<int>, less<int>> q; //降序排序,大根堆 (默认)
map、set
map<int ,int> //默认按键值升序排序 ,默认是map<int, int,less<int>>
map<int, int, greater<int>> //按键值降序排列
set<int> //默认按键值升序排序 ,默认是set<int, less<int>>
set<int, greater<int>> mp({6,4,1,2,7,0}); //按键值降序排列