@@ -46,41 +46,36 @@ findMedian() -> 2
46
46
47
47
<!-- solution:start -->
48
48
49
- ### 方法一:优先队列(双堆 )
49
+ ### 方法一:大小根堆(优先队列 )
50
50
51
- 创建大根堆、小根堆,其中:大根堆存放较小的一半元素,小根堆存放较大的一半元素 。
51
+ 我们可以使用两个堆来维护所有的元素,一个小根堆 $\text{minQ}$ 和一个大根堆 $\text{maxQ}$,其中小根堆 $\text{minQ}$ 存储较大的一半,大根堆 $\text{maxQ}$ 存储较小的一半 。
52
52
53
- 添加元素时,先放入小根堆,然后将小根堆对顶元素弹出并放入大根堆(使得大根堆个数多 $1$);若大小根堆元素个数差超过 $ 1$,则将大根堆元素弹出放入小根堆 。
53
+ 调用 ` addNum ` 方法时,我们首先将元素加入到大根堆 $\text{maxQ}$,然后将 $\text{maxQ}$ 的堆顶元素弹出并加入到小根堆 $\text{minQ}$。如果此时 $\text{minQ}$ 的大小与 $\text{maxQ}$ 的大小差值大于 $ 1$,我们就将 $\text{minQ}$ 的堆顶元素弹出并加入到 $\text{maxQ}$。时间复杂度为 $O(\log n)$ 。
54
54
55
- 取中位数时,若大根堆元素较多,取大根堆堆顶,否则取两堆顶元素和的平均值 。
55
+ 调用 ` findMedian ` 方法时,如果 $\text{minQ}$ 的大小等于 $\text{maxQ}$ 的大小,说明元素的总数为偶数,我们就可以返回 $\text{minQ}$ 的堆顶元素与 $\text{maxQ}$ 的堆顶元素的平均值;否则,我们返回 $\text{minQ}$ 的堆顶元素。时间复杂度为 $O(1)$ 。
56
56
57
- ** 时间复杂度分析:**
58
-
59
- 每次添加元素的时间复杂度为 $O(\log n)$,取中位数的时间复杂度为 $O(1)$。
57
+ 空间复杂度为 $O(n)$。其中 $n$ 为元素的个数。
60
58
61
59
<!-- tabs:start -->
62
60
63
61
#### Python3
64
62
65
63
``` python
66
64
class MedianFinder :
65
+
67
66
def __init__ (self ):
68
- """
69
- initialize your data structure here.
70
- """
71
- self .h1 = []
72
- self .h2 = []
67
+ self .minq = []
68
+ self .maxq = []
73
69
74
70
def addNum (self , num : int ) -> None :
75
- heappush(self .h1, num)
76
- heappush(self .h2, - heappop(self .h1))
77
- if len (self .h2) - len (self .h1) > 1 :
78
- heappush(self .h1, - heappop(self .h2))
71
+ heappush(self .minq, - heappushpop(self .maxq, - num))
72
+ if len (self .minq) - len (self .maxq) > 1 :
73
+ heappush(self .maxq, - heappop(self .minq))
79
74
80
75
def findMedian (self ) -> float :
81
- if len (self .h2) > len (self .h1 ):
82
- return - self .h2 [0 ]
83
- return ( self .h1 [0 ] - self .h2[ 0 ]) / 2
76
+ if len (self .minq) == len (self .maxq ):
77
+ return ( self .minq[ 0 ] - self .maxq [0 ]) / 2
78
+ return self .minq [0 ]
84
79
85
80
86
81
# Your MedianFinder object will be instantiated and called as such:
@@ -93,26 +88,22 @@ class MedianFinder:
93
88
94
89
``` java
95
90
class MedianFinder {
96
- private PriorityQueue<Integer > q1 = new PriorityQueue<> ();
97
- private PriorityQueue<Integer > q2 = new PriorityQueue<> (Collections . reverseOrder());
91
+ private PriorityQueue<Integer > minQ = new PriorityQueue<> ();
92
+ private PriorityQueue<Integer > maxQ = new PriorityQueue<> (Collections . reverseOrder());
98
93
99
- /* * initialize your data structure here. */
100
94
public MedianFinder () {
101
95
}
102
96
103
97
public void addNum (int num ) {
104
- q1 . offer(num);
105
- q2 . offer(q1 . poll());
106
- if (q2 . size() - q1 . size() > 1 ) {
107
- q1 . offer(q2 . poll());
98
+ maxQ . offer(num);
99
+ minQ . offer(maxQ . poll());
100
+ if (minQ . size() - maxQ . size() > 1 ) {
101
+ maxQ . offer(minQ . poll());
108
102
}
109
103
}
110
104
111
105
public double findMedian () {
112
- if (q2. size() > q1. size()) {
113
- return q2. peek();
114
- }
115
- return (q1. peek() + q2. peek()) * 1.0 / 2 ;
106
+ return minQ. size() == maxQ. size() ? (minQ. peek() + maxQ. peek()) / 2.0 : minQ. peek();
116
107
}
117
108
}
118
109
@@ -129,30 +120,27 @@ class MedianFinder {
129
120
``` cpp
130
121
class MedianFinder {
131
122
public:
132
- /** initialize your data structure here. * /
133
123
MedianFinder() {
134
124
}
135
125
136
126
void addNum(int num) {
137
- q1.push(num);
138
- q2.push(q1.top());
139
- q1.pop();
140
- if (q2.size() - q1.size() > 1) {
141
- q1.push(q2.top());
142
- q2.pop();
127
+ maxQ.push(num);
128
+ minQ.push(maxQ.top());
129
+ maxQ.pop();
130
+
131
+ if (minQ.size() > maxQ.size() + 1) {
132
+ maxQ.push(minQ.top());
133
+ minQ.pop();
143
134
}
144
135
}
145
136
146
137
double findMedian () {
147
- if (q2.size() > q1.size()) {
148
- return q2.top();
149
- }
150
- return (double) (q1.top() + q2.top()) / 2;
138
+ return minQ.size() == maxQ.size() ? (minQ.top() + maxQ.top()) / 2.0 : minQ.top();
151
139
}
152
140
153
141
private:
154
- priority_queue<int, vector< int >, greater< int >> q1 ;
155
- priority_queue<int > q2 ;
142
+ priority_queue<int > maxQ ;
143
+ priority_queue<int, vector< int >, greater< int >> minQ ;
156
144
};
157
145
158
146
/* *
@@ -167,37 +155,31 @@ private:
167
155
168
156
``` go
169
157
type MedianFinder struct {
170
- q1 hp
171
- q2 hp
158
+ minq hp
159
+ maxq hp
172
160
}
173
161
174
- /* * initialize your data structure here. */
175
162
func Constructor () MedianFinder {
176
163
return MedianFinder{hp{}, hp{}}
177
164
}
178
165
179
166
func (this *MedianFinder ) AddNum (num int ) {
180
- heap.Push (&this.q1 , num)
181
- heap.Push (&this.q2 , -heap.Pop (&this.q1 ).(int ))
182
- if this.q2 .Len ()-this.q1 .Len () > 1 {
183
- heap.Push (&this.q1 , -heap.Pop (&this.q2 ).(int ))
167
+ minq , maxq := &this.minq , &this.maxq
168
+ heap.Push (maxq, -num)
169
+ heap.Push (minq, -heap.Pop (maxq).(int ))
170
+ if minq.Len ()-maxq.Len () > 1 {
171
+ heap.Push (maxq, -heap.Pop (minq).(int ))
184
172
}
185
173
}
186
174
187
175
func (this *MedianFinder ) FindMedian () float64 {
188
- if this.q2 .Len () > this.q1 .Len () {
189
- return -float64 (this.q2 .IntSlice [0 ])
176
+ minq , maxq := this.minq , this.maxq
177
+ if minq.Len () == maxq.Len () {
178
+ return float64 (minq.IntSlice [0 ]-maxq.IntSlice [0 ]) / 2
190
179
}
191
- return float64 (this. q1 . IntSlice [0 ]-this. q2 . IntSlice [ 0 ]) / 2.0
180
+ return float64 (minq. IntSlice [0 ])
192
181
}
193
182
194
- /* *
195
- * Your MedianFinder object will be instantiated and called as such:
196
- * obj := Constructor();
197
- * obj.AddNum(num);
198
- * param_2 := obj.FindMedian();
199
- */
200
-
201
183
type hp struct { sort.IntSlice }
202
184
203
185
func (h hp ) Less (i , j int ) bool { return h.IntSlice [i] < h.IntSlice [j] }
@@ -208,32 +190,181 @@ func (h *hp) Pop() any {
208
190
h.IntSlice = a[:len (a)-1 ]
209
191
return v
210
192
}
193
+
194
+ /* *
195
+ * Your MedianFinder object will be instantiated and called as such:
196
+ * obj := Constructor();
197
+ * obj.AddNum(num);
198
+ * param_2 := obj.FindMedian();
199
+ */
200
+ ```
201
+
202
+ #### TypeScript
203
+
204
+ ``` ts
205
+ class MedianFinder {
206
+ #minQ = new MinPriorityQueue ();
207
+ #maxQ = new MaxPriorityQueue ();
208
+
209
+ addNum(num : number ): void {
210
+ const [minQ, maxQ] = [this .#minQ , this .#maxQ ];
211
+ maxQ .enqueue (num );
212
+ minQ .enqueue (maxQ .dequeue ().element );
213
+ if (minQ .size () - maxQ .size () > 1 ) {
214
+ maxQ .enqueue (minQ .dequeue ().element );
215
+ }
216
+ }
217
+
218
+ findMedian(): number {
219
+ const [minQ, maxQ] = [this .#minQ , this .#maxQ ];
220
+ if (minQ .size () === maxQ .size ()) {
221
+ return (minQ .front ().element + maxQ .front ().element ) / 2 ;
222
+ }
223
+ return minQ .front ().element ;
224
+ }
225
+ }
226
+
227
+ /**
228
+ * Your MedianFinder object will be instantiated and called as such:
229
+ * var obj = new MedianFinder()
230
+ * obj.addNum(num)
231
+ * var param_2 = obj.findMedian()
232
+ */
233
+ ```
234
+
235
+ #### Rust
236
+
237
+ ``` rust
238
+ use std :: cmp :: Reverse ;
239
+ use std :: collections :: BinaryHeap ;
240
+
241
+ struct MedianFinder {
242
+ minQ: BinaryHeap <Reverse <i32 >>,
243
+ maxQ: BinaryHeap <i32 >,
244
+ }
245
+
246
+ impl MedianFinder {
247
+ fn new () -> Self {
248
+ MedianFinder {
249
+ minQ: BinaryHeap :: new (),
250
+ maxQ: BinaryHeap :: new (),
251
+ }
252
+ }
253
+
254
+ fn add_num (& mut self , num : i32 ) {
255
+ self . maxQ. push (num );
256
+ self . minQ. push (Reverse (self . maxQ. pop (). unwrap ()));
257
+
258
+ if self . minQ. len () > self . maxQ. len () + 1 {
259
+ self . maxQ. push (self . minQ. pop (). unwrap (). 0 );
260
+ }
261
+ }
262
+
263
+ fn find_median (& self ) -> f64 {
264
+ if self . minQ. len () == self . maxQ. len () {
265
+ let min_top = self . minQ. peek (). unwrap (). 0 ;
266
+ let max_top = * self . maxQ. peek (). unwrap ();
267
+ (min_top + max_top ) as f64 / 2.0
268
+ } else {
269
+ self . minQ. peek (). unwrap (). 0 as f64
270
+ }
271
+ }
272
+ }
273
+ ```
274
+
275
+ #### JavaScript
276
+
277
+ ``` js
278
+ var MedianFinder = function () {
279
+ this .minQ = new MinPriorityQueue ();
280
+ this .maxQ = new MaxPriorityQueue ();
281
+ };
282
+
283
+ /**
284
+ * @param {number} num
285
+ * @return {void}
286
+ */
287
+ MedianFinder .prototype .addNum = function (num ) {
288
+ this .maxQ .enqueue (num);
289
+ this .minQ .enqueue (this .maxQ .dequeue ().element );
290
+ if (this .minQ .size () - this .maxQ .size () > 1 ) {
291
+ this .maxQ .enqueue (this .minQ .dequeue ().element );
292
+ }
293
+ };
294
+
295
+ /**
296
+ * @return {number}
297
+ */
298
+ MedianFinder .prototype .findMedian = function () {
299
+ if (this .minQ .size () === this .maxQ .size ()) {
300
+ return (this .minQ .front ().element + this .maxQ .front ().element ) / 2 ;
301
+ }
302
+ return this .minQ .front ().element ;
303
+ };
304
+
305
+ /**
306
+ * Your MedianFinder object will be instantiated and called as such:
307
+ * var obj = new MedianFinder()
308
+ * obj.addNum(num)
309
+ * var param_2 = obj.findMedian()
310
+ */
311
+ ```
312
+
313
+ #### C#
314
+
315
+ ``` cs
316
+ public class MedianFinder {
317
+ private PriorityQueue <int , int > minQ = new PriorityQueue <int , int >();
318
+ private PriorityQueue <int , int > maxQ = new PriorityQueue <int , int >(Comparer <int >.Create ((a , b ) => b .CompareTo (a )));
319
+
320
+ public MedianFinder () {
321
+
322
+ }
323
+
324
+ public void AddNum (int num ) {
325
+ maxQ .Enqueue (num , num );
326
+ minQ .Enqueue (maxQ .Peek (), maxQ .Dequeue ());
327
+ if (minQ .Count > maxQ .Count + 1 ) {
328
+ maxQ .Enqueue (minQ .Peek (), minQ .Dequeue ());
329
+ }
330
+ }
331
+
332
+ public double FindMedian () {
333
+ return minQ .Count == maxQ .Count ? (minQ .Peek () + maxQ .Peek ()) / 2 . 0 : minQ .Peek ();
334
+ }
335
+ }
336
+
337
+ /**
338
+ * Your MedianFinder object will be instantiated and called as such:
339
+ * MedianFinder obj = new MedianFinder();
340
+ * obj.AddNum(num);
341
+ * double param_2 = obj.FindMedian();
342
+ */
211
343
```
212
344
213
345
#### Swift
214
346
215
347
``` swift
216
348
class MedianFinder {
217
- private var minHeap = Heap< Int > (sort : < )
218
- private var maxHeap = Heap< Int > (sort : > )
349
+ private var minQ = Heap< Int > (sort : < )
350
+ private var maxQ = Heap< Int > (sort : > )
219
351
220
352
init () {
221
353
}
222
354
223
355
func addNum (_ num : Int ) {
224
- maxHeap.insert (num)
225
- minHeap.insert (maxHeap.remove ()! )
226
-
227
- if maxHeap.count < minHeap.count {
228
- maxHeap.insert (minHeap.remove ()! )
356
+ maxQ.insert (num)
357
+ minQ.insert (maxQ.remove ()! )
358
+ if maxQ.count < minQ.count {
359
+ maxQ.insert (minQ.remove ()! )
229
360
}
230
361
}
231
362
232
363
func findMedian () -> Double {
233
- if maxHeap .count > minHeap .count {
234
- return Double (maxHeap .peek ()! )
364
+ if maxQ .count > minQ .count {
365
+ return Double (maxQ .peek ()! )
235
366
}
236
- return (Double (maxHeap .peek ()! ) + Double (minHeap .peek ()! )) / 2.0
367
+ return (Double (maxQ .peek ()! ) + Double (minQ .peek ()! )) / 2.0
237
368
}
238
369
}
239
370
@@ -318,6 +449,13 @@ struct Heap<T> {
318
449
return 2 * index + 2
319
450
}
320
451
}
452
+
453
+ /**
454
+ * Your MedianFinder object will be instantiated and called as such:
455
+ * let obj = MedianFinder()
456
+ * obj.addNum(num)
457
+ * let ret_2: Double = obj.findMedian()
458
+ */
321
459
```
322
460
323
461
<!-- tabs:end -->
0 commit comments