原题链接: Leetcode 295. 数据流的中位数
中位数查找思想:用两个堆维护数据(大顶堆存左半部分数据,小顶堆存右半部分数据),堆顶分别为左半最大值和右半最小值,可 O (1) 获取中位数。
解法1:官解
cpp
class MedianFinder {
public:
//大顶堆存左半部分数据, 堆顶为左半最大值
priority_queue<int, vector<int> ,less<int>> quemin;
// 小顶堆存右半部分数据, 堆顶为右半最小值
priority_queue<int, vector<int> ,greater<int>> quemax;
MedianFinder() {
}
// 整个序列长度偶数:quemin长度=quemax长度
// 整个序列长度奇数:quemin长度=quemax长度+1
void addNum(int num) {
if(quemin.empty() || num<=quemin.top()){
quemin.push(num);
if(quemax.size()+1<quemin.size()){
quemax.push(quemin.top());
quemin.pop();
}
}
else{
quemax.push(num);
if(quemax.size()>quemin.size()){
quemin.push(quemax.top());
quemax.pop();
}
}
}
double findMedian() {
if(quemin.size() > quemax.size()) return quemin.top();
return (quemin.top()+quemax.top()) / 2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/
解法2:
参考: 如何自然引入大小堆?简洁写法!(Python/Java/C++/Go/JS/Rust)
- 如果整个序列长度偶数:left长度 = right长度
- 如果整个序列长度奇数:left长度 = right长度+1
加入数字的过程中, 要时时刻刻满足以上两个要求,就可以用 left 中的最大值以及 right 中的最小值计算中位数。
分类讨论:
- 如果当前 left 的大小和 right 的大小相等:
- 如果添加的数字 num 比较大
- 如果添加的数字 num 比较小
- 如果当前 left 比 right 多 1 个数:
- 如果添加的数字 num 比较大
- 如果添加的数字 num 比较小
cpp
class MedianFinder {
public:
//大顶堆存左半部分数据, 堆顶为左半最大值
priority_queue<int, vector<int> ,less<int>> left;
// 小顶堆存右半部分数据, 堆顶为右半最小值
priority_queue<int, vector<int> ,greater<int>> right;
MedianFinder() {
}
// 整个序列长度偶数:left长度=right长度
// 整个序列长度奇数:left长度=right长度+1
void addNum(int num) {
if(left.size()==right.size()){
right.push(num);
left.push(right.top());
right.pop();
}
else{
left.push(num);
right.push(left.top());
left.pop();
}
}
double findMedian() {
if(left.size() > right.size()) return left.top();
return (left.top()+right.top()) / 2.0;
}
};
/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* obj->addNum(num);
* double param_2 = obj->findMedian();
*/