# Leetcode 数据流中的中位数：双堆

### LC 295. 数据流的中位数

class MedianFinder {
public:
/** initialize your data structure here. */
priority_queue<int>leftQ;  // 左边是大根堆
priority_queue<int, vector<int>, greater<int>>rightQ;
MedianFinder() {

}

if(leftQ.empty() || num <= leftQ.top()) {
leftQ.push(num);
if(leftQ.size() - rightQ.size() > 1) {
int tmp = leftQ.top();leftQ.pop();
rightQ.push(tmp);
}
} else {
rightQ.push(num);
if(rightQ.size() - leftQ.size() > 1) {
int tmp = rightQ.top();rightQ.pop();
leftQ.push(tmp);
}
}
}

double findMedian() {
if(leftQ.size() > rightQ.size())  return leftQ.top();
else if(leftQ.size() == rightQ.size())  return (leftQ.top() + rightQ.top()) *1.0 / 2;
else  return rightQ.top();
}
};

/**
* Your MedianFinder object will be instantiated and called as such:
* MedianFinder* obj = new MedianFinder();
* double param_2 = obj->findMedian();
*/


### LC 480. 滑动窗口中位数

#### 方法一：双堆+延迟删除

class Solution {
public:
priority_queue<int>leftQ;
priority_queue<int, vector<int>, greater<int>>rightQ;
unordered_map<int, int>mp;
int leftCnt, rightCnt;
if(leftCnt - rightCnt > 1) {
int tmp = leftQ.top();leftQ.pop();leftCnt--;
rightQ.push(tmp);rightCnt++;
}
if(rightCnt- leftCnt > 1) {
int tmp = rightQ.top();rightQ.pop();rightCnt--;
leftQ.push(tmp);leftCnt++;
}
}
if(leftQ.empty() && (!rightQ.empty())) {  // k=1的时候，会出现左边为空，而右边有元素的情况
int tmp = rightQ.top();rightQ.pop();rightCnt--;
leftQ.push(tmp);leftCnt++;
}
if(leftQ.empty() || num < leftQ.top()) {
leftQ.push(num);leftCnt++;
} else {
rightQ.push(num);rightCnt++;
}
}
void deleteItem(int num) {
mp[num]++;   // 记录删除了的
if(num <= leftQ.top())  leftCnt--; // 要用小于等于，因为可能要删除的就是队首
else  rightCnt--;
}
void pure() {
while((!leftQ.empty()) && mp[leftQ.top()]) {
mp[leftQ.top()]--;
leftQ.pop();
}
while((!rightQ.empty()) && mp[rightQ.top()]) {
mp[rightQ.top()]--;
rightQ.pop();
}
}
double getMedian() {
pure();  // 清理堆头
if(leftCnt > rightCnt)  return leftQ.top();
else if(leftCnt < rightCnt)  return rightQ.top();
return ((long long)leftQ.top() + (long long)rightQ.top()) * 1.0 / 2;
}

vector<double> medianSlidingWindow(vector<int>& nums, int k) {
int i = 0, j = 0;
while(j < k) {
j++;
}
vector<double>ans;
ans.push_back(getMedian());

while(j < nums.size()) {
deleteItem(nums[i++]);
ans.push_back(getMedian());
}
return ans;
}
};


#### 方法二：pbds tree

#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;

// alias template
template <typename T>
using orderd_set = tree<T, null_type, less<T>, rb_tree_tag, tree_order_statistics_node_update>;

class Solution {
public:
tree<pair<int,int>, null_type, less<pair<int, int>>, rb_tree_tag, tree_order_statistics_node_update> order_set;
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double>ans;
orderd_set<pair<int, int>>myset;
for(int i = 0;i < nums.size();i++) {
if(i < k)  myset.insert({nums[i], i});
else {
if(k&1)  ans.push_back((*myset.find_by_order(k/2)).first);
else ans.push_back(((long long)(*myset.find_by_order(k/2)).first + (long long)(*myset.find_by_order(k/2-1)).first)*1.0/2);
myset.insert({nums[i], i});
myset.erase({nums[i-k], i-k});
}
}
if(k&1)  ans.push_back((*myset.find_by_order(k/2)).first);
else ans.push_back(((long long)(*myset.find_by_order(k/2)).first + (long long)(*myset.find_by_order(k/2-1)).first)*1.0/2);
return ans;
}
};


class Solution {
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k) {
vector<double>ans;
multiset<double>myset;
for(int i = 0;i < nums.size();i++) {
if(i < k)  myset.insert(nums[i]);
else {
auto p = myset.begin();
if(k&1)  ans.push_back(*p);
else ans.push_back(((long long)*p+ (long long)(*prev(p, 1)))*1.0/2);
myset.insert(nums[i]);
myset.erase(myset.find(nums[i-k]));
}
}
auto p = myset.begin();
if(k&1)  ans.push_back(*p);  // 最后还有一次
else ans.push_back(((long long)*p+ (long long)(*prev(p, 1)))*1.0/2);
return ans;
}
};


### 参考链接

posted @ 2022-01-13 18:02  Rogn  阅读(17)  评论(0编辑  收藏  举报