@@ -102,7 +102,23 @@ statisticsTracker.getMode(); // return 5</div>
102102
103103<!-- solution:start -->
104104
105- ### 方法一
105+ ### 方法一:队列 + 哈希表 + 有序集合
106+
107+ 我们定义一个队列 $\textit{q}$,用来存储添加的数字,一个变量 $\textit{s}$,用来存储所有数字的和,一个哈希表 $\textit{cnt}$,用来存储每个数字的出现次数,一个有序集合 $\textit{sl}$,用来存储所有数字,一个有序集合 $\textit{sl2}$,用来存储所有数字及其出现次数,按照出现次数降序、数值升序的顺序。
108+
109+ 在 ` addNumber ` 方法中,我们将数字添加到队列 $\textit{q}$ 中,将数字添加到有序集合 $\textit{sl}$ 中,然后先将数字及其出现次数从有序集合 $\textit{sl2}$ 中删除,再更新数字的出现次数,最后将数字及其出现次数添加到有序集合 $\textit{sl2}$ 中,并更新所有数字的和。时间复杂度为 $O(\log n)$。
110+
111+ 在 ` removeFirstAddedNumber ` 方法中,我们从队列 $\textit{q}$ 中删除最早添加的数字,从有序集合 $\textit{sl}$ 中删除数字,然后先将数字及其出现次数从有序集合 $\textit{sl2}$ 中删除,再更新数字的出现次数,最后将数字及其出现次数添加到有序集合 $\textit{sl2}$ 中,并更新所有数字的和。时间复杂度为 $O(\log n)$。
112+
113+ 在 ` getMean ` 方法中,我们返回所有数字的和除以数字的数量,时间复杂度为 $O(1)$。
114+
115+ 在 ` getMedian ` 方法中,我们返回有序集合 $\textit{sl}$ 中的第 $\textit{len}(\textit{q}) / 2$ 个数字,时间复杂度为 $O(1)$ 或 $O(\log n)$。
116+
117+ 在 ` getMode ` 方法中,我们返回有序集合 $\textit{sl2}$ 中的第一个数字,时间复杂度 $O(1)$。
118+
119+ > 在 Python 中,我们可以直接按下标获取有序集合中的元素,在其它语言中,我们可以通过对顶堆实现。
120+
121+ 空间复杂度 $O(n)$,其中 $n$ 为添加的数字的数量。
106122
107123<!-- tabs:start -->
108124
@@ -159,13 +175,225 @@ class StatisticsTracker:
159175#### Java
160176
161177``` java
162-
178+ class MedianFinder {
179+ private final PriorityQueue<Integer > small = new PriorityQueue<> (Comparator . reverseOrder());
180+ private final PriorityQueue<Integer > large = new PriorityQueue<> ();
181+ private final Map<Integer , Integer > delayed = new HashMap<> ();
182+ private int smallSize;
183+ private int largeSize;
184+
185+ public void addNum (int num ) {
186+ if (small. isEmpty() || num <= small. peek()) {
187+ small. offer(num);
188+ ++ smallSize;
189+ } else {
190+ large. offer(num);
191+ ++ largeSize;
192+ }
193+ rebalance();
194+ }
195+
196+ public Integer findMedian () {
197+ return smallSize == largeSize ? large. peek() : small. peek();
198+ }
199+
200+ public void removeNum (int num ) {
201+ delayed. merge(num, 1 , Integer :: sum);
202+ if (num <= small. peek()) {
203+ -- smallSize;
204+ if (num == small. peek()) {
205+ prune(small);
206+ }
207+ } else {
208+ -- largeSize;
209+ if (num == large. peek()) {
210+ prune(large);
211+ }
212+ }
213+ rebalance();
214+ }
215+
216+ private void prune (PriorityQueue<Integer > pq ) {
217+ while (! pq. isEmpty() && delayed. containsKey(pq. peek())) {
218+ if (delayed. merge(pq. peek(), - 1 , Integer :: sum) == 0 ) {
219+ delayed. remove(pq. peek());
220+ }
221+ pq. poll();
222+ }
223+ }
224+
225+ private void rebalance () {
226+ if (smallSize > largeSize + 1 ) {
227+ large. offer(small. poll());
228+ -- smallSize;
229+ ++ largeSize;
230+ prune(small);
231+ } else if (smallSize < largeSize) {
232+ small. offer(large. poll());
233+ -- largeSize;
234+ ++ smallSize;
235+ prune(large);
236+ }
237+ }
238+ }
239+
240+ class StatisticsTracker {
241+ private final Deque<Integer > q = new ArrayDeque<> ();
242+ private long s;
243+ private final Map<Integer , Integer > cnt = new HashMap<> ();
244+ private final MedianFinder medianFinder = new MedianFinder ();
245+ private final TreeSet<int[]> ts
246+ = new TreeSet<> ((a, b) - > a[1 ] == b[1 ] ? a[0 ] - b[0 ] : b[1 ] - a[1 ]);
247+
248+ public StatisticsTracker () {
249+ }
250+
251+ public void addNumber (int number ) {
252+ q. offerLast(number);
253+ s += number;
254+ ts. remove(new int [] {number, cnt. getOrDefault(number, 0 )});
255+ cnt. merge(number, 1 , Integer :: sum);
256+ medianFinder. addNum(number);
257+ ts. add(new int [] {number, cnt. get(number)});
258+ }
259+
260+ public void removeFirstAddedNumber () {
261+ int number = q. pollFirst();
262+ s -= number;
263+ ts. remove(new int [] {number, cnt. get(number)});
264+ cnt. merge(number, - 1 , Integer :: sum);
265+ medianFinder. removeNum(number);
266+ ts. add(new int [] {number, cnt. get(number)});
267+ }
268+
269+ public int getMean () {
270+ return (int ) (s / q. size());
271+ }
272+
273+ public int getMedian () {
274+ return medianFinder. findMedian();
275+ }
276+
277+ public int getMode () {
278+ return ts. first()[0 ];
279+ }
280+ }
163281```
164282
165283#### C++
166284
167285``` cpp
168-
286+ class MedianFinder {
287+ public:
288+ void addNum(int num) {
289+ if (small.empty() || num <= small.top()) {
290+ small.push(num);
291+ ++smallSize;
292+ } else {
293+ large.push(num);
294+ ++largeSize;
295+ }
296+ reblance();
297+ }
298+
299+ void removeNum(int num) {
300+ ++delayed[num];
301+ if (num <= small.top()) {
302+ --smallSize;
303+ if (num == small.top()) {
304+ prune(small);
305+ }
306+ } else {
307+ --largeSize;
308+ if (num == large.top()) {
309+ prune (large);
310+ }
311+ }
312+ reblance();
313+ }
314+
315+ int findMedian() {
316+ return smallSize == largeSize ? large.top() : small.top();
317+ }
318+
319+ private:
320+ priority_queue<int > small;
321+ priority_queue<int, vector<int >, greater<int >> large;
322+ unordered_map<int, int> delayed;
323+ int smallSize = 0;
324+ int largeSize = 0;
325+
326+ template <typename T>
327+ void prune(T& pq) {
328+ while (!pq.empty() && delayed[pq.top()]) {
329+ if (--delayed[pq.top()] == 0) {
330+ delayed.erase(pq.top());
331+ }
332+ pq.pop();
333+ }
334+ }
335+
336+ void reblance() {
337+ if (smallSize > largeSize + 1) {
338+ large.push(small.top());
339+ small.pop();
340+ --smallSize;
341+ ++largeSize;
342+ prune (small);
343+ } else if (smallSize < largeSize) {
344+ small.push(large.top());
345+ large.pop();
346+ ++smallSize;
347+ --largeSize;
348+ prune(large);
349+ }
350+ }
351+ };
352+
353+ class StatisticsTracker {
354+ private:
355+ queue<int > q;
356+ long long s = 0;
357+ unordered_map<int, int> cnt;
358+ MedianFinder medianFinder;
359+ set<pair<int, int>> ts;
360+
361+ public:
362+ StatisticsTracker() {}
363+
364+ void addNumber(int number) {
365+ q.push(number);
366+ s += number;
367+ ts.erase({-cnt[number], number});
368+ cnt[number]++;
369+ medianFinder.addNum(number);
370+ ts.insert({-cnt[number], number});
371+ }
372+
373+ void removeFirstAddedNumber () {
374+ int number = q.front();
375+ q.pop();
376+ s -= number;
377+ ts.erase({-cnt[number], number});
378+ cnt[number]--;
379+ if (cnt[number] > 0) {
380+ ts.insert({-cnt[number], number});
381+ }
382+ medianFinder.removeNum(number);
383+ }
384+
385+ int getMean() {
386+ return static_cast<int>(s / q.size());
387+ }
388+
389+ int getMedian() {
390+ return medianFinder.findMedian();
391+ }
392+
393+ int getMode() {
394+ return ts.begin()->second;
395+ }
396+ };
169397```
170398
171399#### Go
0 commit comments