Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 36d3a40

Browse files
feat: add solutions to lcci/lcof problems (doocs#3170)
lcci 17.20 & lcof 41. Continuous Median
1 parent 92af611 commit 36d3a40

File tree

22 files changed

+876
-645
lines changed

22 files changed

+876
-645
lines changed

‎lcci/17.20.Continuous Median/README.md‎

Lines changed: 208 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -46,41 +46,36 @@ findMedian() -> 2
4646

4747
<!-- solution:start -->
4848

49-
### 方法一:优先队列(双堆)
49+
### 方法一:大小根堆(优先队列)
5050

51-
创建大根堆、小根堆,其中:大根堆存放较小的一半元素,小根堆存放较大的一半元素
51+
我们可以使用两个堆来维护所有的元素,一个小根堆 $\text{minQ}$ 和一个大根堆 $\text{maxQ},ドル其中小根堆 $\text{minQ}$ 存储较大的一半,大根堆 $\text{maxQ}$ 存储较小的一半
5252

53-
添加元素时,先放入小根堆,然后将小根堆对顶元素弹出并放入大根堆(使得大根堆个数多 1ドル$);若大小根堆元素个数差超过 $1,ドル则将大根堆元素弹出放入小根堆
53+
调用 `addNum` 方法时,我们首先将元素加入到大根堆 $\text{maxQ},ドル然后将 $\text{maxQ}$ 的堆顶元素弹出并加入到小根堆 $\text{minQ}$。如果此时 $\text{minQ}$ 的大小与 $\text{maxQ}$ 的大小差值大于 $1,ドル我们就将 $\text{minQ}$ 的堆顶元素弹出并加入到 $\text{maxQ}$。时间复杂度为 $O(\log n)$
5454

55-
取中位数时,若大根堆元素较多,取大根堆堆顶,否则取两堆顶元素和的平均值
55+
调用 `findMedian` 方法时,如果 $\text{minQ}$ 的大小等于 $\text{maxQ}$ 的大小,说明元素的总数为偶数,我们就可以返回 $\text{minQ}$ 的堆顶元素与 $\text{maxQ}$ 的堆顶元素的平均值;否则,我们返回 $\text{minQ}$ 的堆顶元素。时间复杂度为 $O(1)$
5656

57-
**时间复杂度分析:**
58-
59-
每次添加元素的时间复杂度为 $O(\log n),ドル取中位数的时间复杂度为 $O(1)$。
57+
空间复杂度为 $O(n)$。其中 $n$ 为元素的个数。
6058

6159
<!-- tabs:start -->
6260

6361
#### Python3
6462

6563
```python
6664
class MedianFinder:
65+
6766
def __init__(self):
68-
"""
69-
initialize your data structure here.
70-
"""
71-
self.h1 = []
72-
self.h2 = []
67+
self.minq = []
68+
self.maxq = []
7369

7470
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))
7974

8075
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]
8479

8580

8681
# Your MedianFinder object will be instantiated and called as such:
@@ -93,26 +88,22 @@ class MedianFinder:
9388

9489
```java
9590
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());
9893

99-
/** initialize your data structure here. */
10094
public MedianFinder() {
10195
}
10296

10397
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());
108102
}
109103
}
110104

111105
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();
116107
}
117108
}
118109

@@ -129,30 +120,27 @@ class MedianFinder {
129120
```cpp
130121
class MedianFinder {
131122
public:
132-
/** initialize your data structure here. */
133123
MedianFinder() {
134124
}
135125

136126
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();
143134
}
144135
}
145136

146137
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();
151139
}
152140

153141
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;
156144
};
157145

158146
/**
@@ -167,37 +155,31 @@ private:
167155

168156
```go
169157
type MedianFinder struct {
170-
q1 hp
171-
q2 hp
158+
minq hp
159+
maxq hp
172160
}
173161

174-
/** initialize your data structure here. */
175162
func Constructor() MedianFinder {
176163
return MedianFinder{hp{}, hp{}}
177164
}
178165

179166
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))
184172
}
185173
}
186174

187175
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
190179
}
191-
return float64(this.q1.IntSlice[0]-this.q2.IntSlice[0]) / 2.0
180+
return float64(minq.IntSlice[0])
192181
}
193182

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-
201183
type hp struct{ sort.IntSlice }
202184

203185
func (h hp) Less(i, j int) bool { return h.IntSlice[i] < h.IntSlice[j] }
@@ -208,32 +190,181 @@ func (h *hp) Pop() any {
208190
h.IntSlice = a[:len(a)-1]
209191
return v
210192
}
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+
*/
211343
```
212344

213345
#### Swift
214346

215347
```swift
216348
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: >)
219351

220352
init() {
221353
}
222354

223355
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()!)
229360
}
230361
}
231362

232363
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()!)
235366
}
236-
return (Double(maxHeap.peek()!) + Double(minHeap.peek()!)) / 2.0
367+
return (Double(maxQ.peek()!) + Double(minQ.peek()!)) / 2.0
237368
}
238369
}
239370

@@ -318,6 +449,13 @@ struct Heap<T> {
318449
return 2 * index + 2
319450
}
320451
}
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+
*/
321459
```
322460

323461
<!-- tabs:end -->

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /