48
48
49
49
<!-- 这里可写通用的实现逻辑 -->
50
50
51
- ** 方法一:优先队列(双堆 )**
51
+ ** 方法一:优先队列(大小根堆 )**
52
52
53
- 创建大根堆、小根堆,其中:大根堆存放较小的一半元素,小根堆存放较大的一半元素 。
53
+ 我们可以维护两个优先队列,一个大根堆,一个小根堆,大根堆存储较小的一半数,小根堆存储较大的一半数 。
54
54
55
- 添加元素时,先放入小根堆,然后将小根堆对顶元素弹出并放入大根堆(使得大根堆个数多 $1$);若大小根堆元素个数差超过 $1$,则将大根堆元素弹出放入小根堆 。
55
+ 当两个堆的元素个数相同时,我们优先往小根堆中添加元素,这样会使得小根堆元素个数比大根堆多 $1$,这样中位数就可以从小根堆中取出 。
56
56
57
- 取中位数时,若大根堆元素较多,取大根堆堆顶,否则取两堆顶元素和的平均值 。
57
+ 当两个堆的元素个数不同时,说明此时小根堆元素个数比大根堆多 $1$,我们往大根堆中添加元素,这样会使得两个堆元素个数相同,这样中位数就可以从两个堆中取出 。
58
58
59
- ** 时间复杂度分析:**
60
-
61
- 每次添加元素的时间复杂度为 $O(\log n)$,取中位数的时间复杂度为 $O(1)$。
59
+ 时间复杂度方面,添加元素的时间复杂度为 $O(\log n)$,查找中位数的时间复杂度为 $O(1)$。空间复杂度为 $O(n)$。其中 $n$ 为数据流中元素的个数。
62
60
63
61
<!-- tabs:start -->
64
62
68
66
69
67
``` python
70
68
class MedianFinder :
69
+ def __init__ (self ):
70
+ """
71
+ initialize your data structure here.
72
+ """
73
+ self .q1 = []
74
+ self .q2 = []
75
+
76
+ def addNum (self , num : int ) -> None :
77
+ if len (self .q1) > len (self .q2):
78
+ heappush(self .q2, - heappushpop(self .q1, num))
79
+ else :
80
+ heappush(self .q1, - heappushpop(self .q2, - num))
81
+
82
+ def findMedian (self ) -> float :
83
+ if len (self .q1) > len (self .q2):
84
+ return self .q1[0 ]
85
+ return (self .q1[0 ] - self .q2[0 ]) / 2
86
+
87
+
88
+ # Your MedianFinder object will be instantiated and called as such:
89
+ # obj = MedianFinder()
90
+ # obj.addNum(num)
91
+ # param_2 = obj.findMedian()
92
+ ```
93
+
94
+ ``` python
95
+ from sortedcontainers import SortedList
71
96
97
+
98
+ class MedianFinder :
72
99
def __init__ (self ):
73
100
"""
74
101
initialize your data structure here.
75
102
"""
76
- self .h1 = []
77
- self .h2 = []
103
+ self .sl = SortedList()
78
104
79
105
def addNum (self , num : int ) -> None :
80
- heappush(self .h1, num)
81
- heappush(self .h2, - heappop(self .h1))
82
- if len (self .h2) - len (self .h1) > 1 :
83
- heappush(self .h1, - heappop(self .h2))
106
+ self .sl.add(num)
84
107
85
108
def findMedian (self ) -> float :
86
- if len (self .h2) > len (self .h1):
87
- return - self .h2[0 ]
88
- return (self .h1[0 ] - self .h2[0 ]) / 2
109
+ n = len (self .sl)
110
+ if n & 1 :
111
+ return self .sl[n // 2 ]
112
+ return (self .sl[(n - 1 ) // 2 ] + self .sl[n // 2 ]) / 2
89
113
90
114
91
115
# Your MedianFinder object will be instantiated and called as such:
@@ -101,26 +125,28 @@ class MedianFinder:
101
125
``` java
102
126
class MedianFinder {
103
127
private PriorityQueue<Integer > q1 = new PriorityQueue<> ();
104
- private PriorityQueue<Integer > q2 = new PriorityQueue<> (Collections . reverseOrder() );
128
+ private PriorityQueue<Integer > q2 = new PriorityQueue<> ((a, b) - > b - a );
105
129
106
130
/* * initialize your data structure here. */
107
131
public MedianFinder () {
108
132
109
133
}
110
134
111
135
public void addNum (int num ) {
112
- q1. offer(num);
113
- q2. offer(q1. poll());
114
- if (q2. size() - q1. size() > 1 ) {
136
+ if (q1. size() > q2. size()) {
137
+ q1. offer(num);
138
+ q2. offer(q1. poll());
139
+ } else {
140
+ q2. offer(num);
115
141
q1. offer(q2. poll());
116
142
}
117
143
}
118
144
119
145
public double findMedian () {
120
- if (q2 . size() > q1 . size()) {
121
- return q2 . peek();
146
+ if (q1 . size() > q2 . size()) {
147
+ return q1 . peek();
122
148
}
123
- return (q1. peek() + q2. peek()) * 1.0 / 2 ;
149
+ return (q1. peek() + q2. peek()) / 2.0 ;
124
150
}
125
151
}
126
152
@@ -143,20 +169,22 @@ public:
143
169
}
144
170
145
171
void addNum (int num) {
146
- q1.push(num);
147
- q2.push(q1.top());
148
- q1.pop();
149
- if (q2.size() - q1.size() > 1) {
172
+ if (q1.size() > q2.size()) {
173
+ q1.push(num);
174
+ q2.push(q1.top());
175
+ q1.pop();
176
+ } else {
177
+ q2.push(num);
150
178
q1.push(q2.top());
151
179
q2.pop();
152
180
}
153
181
}
154
182
155
183
double findMedian() {
156
- if (q2 .size() > q1 .size()) {
157
- return q2 .top();
184
+ if (q1 .size() > q2 .size()) {
185
+ return q1 .top();
158
186
}
159
- return (double) ( q1.top() + q2.top()) / 2;
187
+ return (q1.top() + q2.top()) / 2.0 ;
160
188
}
161
189
162
190
private:
@@ -176,8 +204,7 @@ private:
176
204
177
205
```go
178
206
type MedianFinder struct {
179
- q1 hp
180
- q2 hp
207
+ q1, q2 hp
181
208
}
182
209
183
210
/** initialize your data structure here. */
@@ -186,27 +213,22 @@ func Constructor() MedianFinder {
186
213
}
187
214
188
215
func (this *MedianFinder) AddNum(num int) {
189
- heap.Push(&this.q1, num)
190
- heap.Push(&this.q2, -heap.Pop(&this.q1).(int))
191
- if this.q2.Len()-this.q1.Len() > 1 {
216
+ if this.q1.Len() > this.q2.Len() {
217
+ heap.Push(&this.q1, num)
218
+ heap.Push(&this.q2, -heap.Pop(&this.q1).(int))
219
+ } else {
220
+ heap.Push(&this.q2, -num)
192
221
heap.Push(&this.q1, -heap.Pop(&this.q2).(int))
193
222
}
194
223
}
195
224
196
225
func (this *MedianFinder) FindMedian() float64 {
197
- if this.q2 .Len() > this.q1 .Len() {
198
- return - float64(this.q2 .IntSlice[0])
226
+ if this.q1 .Len() > this.q2 .Len() {
227
+ return float64(this.q1 .IntSlice[0])
199
228
}
200
229
return float64(this.q1.IntSlice[0]-this.q2.IntSlice[0]) / 2.0
201
230
}
202
231
203
- /**
204
- * Your MedianFinder object will be instantiated and called as such:
205
- * obj := Constructor();
206
- * obj.AddNum(num);
207
- * param_2 := obj.FindMedian();
208
- */
209
-
210
232
type hp struct{ sort.IntSlice }
211
233
212
234
func (h hp) Less(i, j int) bool { return h.IntSlice[i] < h.IntSlice[j] }
@@ -217,6 +239,13 @@ func (h *hp) Pop() interface{} {
217
239
h.IntSlice = a[:len(a)-1]
218
240
return v
219
241
}
242
+
243
+ /**
244
+ * Your MedianFinder object will be instantiated and called as such:
245
+ * obj := Constructor();
246
+ * obj.AddNum(num);
247
+ * param_2 := obj.FindMedian();
248
+ */
220
249
```
221
250
222
251
### ** JavaScript**
0 commit comments