-
Notifications
You must be signed in to change notification settings - Fork 0
/
Problem_0480_medianSlidingWindow.cc
146 lines (134 loc) · 3.26 KB
/
Problem_0480_medianSlidingWindow.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#include <functional>
#include <queue>
#include <unordered_map>
#include <vector>
using namespace std;
// 此题是 Problem_0295_MedianFinder.cc 的进阶题
// 延迟删除
// 我们保证在任意操作 insert(num),erase(num),getMedian()
// 完成之后(或者说任意操作开始之前),small 和 large
// 的堆顶元素都是不需要被「延迟删除」的。
// 这样设计的好处在于:我们无需更改 getMedian() 的设计,只需要略加修改 insert(num) 即可。
class DualHeap
{
private:
// 大根堆,维护较小的一半元素
priority_queue<int, vector<int>, less<int>> small;
// 小根堆,维护较大的一半元素
priority_queue<int, vector<int>, greater<int>> large;
// 哈希表,记录「延迟删除」的元素,key 为元素,value 为需要删除的次数
unordered_map<int, int> delayed;
int k;
// small 和 large 当前包含的元素个数,需要扣除被「延迟删除」的元素
int smallSize, largeSize;
public:
DualHeap(int _k) : k(_k), smallSize(0), largeSize(0) {}
private:
// 不断地弹出 heap 的堆顶元素,并且更新哈希表
template <typename T>
void prune(T& heap)
{
while (!heap.empty())
{
int num = heap.top();
if (delayed.count(num))
{
--delayed[num];
if (!delayed[num])
{
delayed.erase(num);
}
heap.pop();
}
else
{
break;
}
}
}
// 调整 small 和 large 中的元素个数,使得二者的元素个数满足要求
void makeBalance()
{
if (smallSize > largeSize + 1)
{
// small 比 large 元素多 2 个
large.push(small.top());
small.pop();
--smallSize;
++largeSize;
// small 堆顶元素被移除,需要进行 prune
prune(small);
}
else if (smallSize < largeSize)
{
// large 比 small 元素多 1 个
small.push(large.top());
large.pop();
++smallSize;
--largeSize;
// large 堆顶元素被移除,需要进行 prune
prune(large);
}
}
public:
void insert(int num)
{
if (small.empty() || num <= small.top())
{
small.push(num);
++smallSize;
}
else
{
large.push(num);
++largeSize;
}
makeBalance();
}
void erase(int num)
{
++delayed[num];
if (num <= small.top())
{
--smallSize;
// 需要保证两个堆的堆顶都不是delayed存在的元素
// 因此这个条件不能删除
if (num == small.top())
{
prune(small);
}
}
else
{
--largeSize;
// 需要保证两个堆的堆顶都不是delayed存在的元素
// 因此这个条件不能删除
if (num == large.top())
{
prune(large);
}
}
makeBalance();
}
double getMedian() { return k & 1 ? small.top() : ((double) small.top() + large.top()) / 2; }
};
class Solution
{
public:
vector<double> medianSlidingWindow(vector<int>& nums, int k)
{
DualHeap dh(k);
for (int i = 0; i < k; ++i)
{
dh.insert(nums[i]);
}
vector<double> ans = {dh.getMedian()};
for (int i = k; i < nums.size(); ++i)
{
dh.insert(nums[i]);
dh.erase(nums[i - k]);
ans.push_back(dh.getMedian());
}
return ans;
}
};