Skip to content

Commit 19066da

Browse files
committed
feat(soobing): week13 > find-median-from-data-stream
1 parent 6cf1de5 commit 19066da

File tree

1 file changed

+131
-0
lines changed

1 file changed

+131
-0
lines changed
Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
/**
2+
* 문제 설명
3+
* - 중간 값을 찾는 문제
4+
*
5+
* 아이디어 (👀 어려움..)
6+
* - 최대 힙과 최소 힙을 사용하여 중간 값을 찾는다.
7+
*/
8+
class MinHeap {
9+
heap: number[] = [];
10+
size(): number {
11+
return this.heap.length;
12+
}
13+
peek(): number | null {
14+
return this.heap[0] ?? null;
15+
}
16+
push(val: number) {
17+
this.heap.push(val);
18+
this.bubbleUp(this.size() - 1);
19+
}
20+
pop(): number | null {
21+
if (this.size() === 0) return null;
22+
const top = this.heap[0];
23+
const end = this.heap.pop()!;
24+
if (this.size() > 0) {
25+
this.heap[0] = end;
26+
this.bubbleDown(0);
27+
}
28+
return top;
29+
}
30+
private bubbleUp(idx: number) {
31+
while (idx > 0) {
32+
const parent = Math.floor((idx - 1) / 2);
33+
if (this.heap[parent] <= this.heap[idx]) break;
34+
[this.heap[parent], this.heap[idx]] = [this.heap[idx], this.heap[parent]];
35+
idx = parent;
36+
}
37+
}
38+
private bubbleDown(idx: number) {
39+
const n = this.size();
40+
while (true) {
41+
let left = idx * 2 + 1;
42+
let right = idx * 2 + 2;
43+
let smallest = idx;
44+
if (left < n && this.heap[left] < this.heap[smallest]) smallest = left;
45+
if (right < n && this.heap[right] < this.heap[smallest]) smallest = right;
46+
if (smallest === idx) break;
47+
[this.heap[smallest], this.heap[idx]] = [
48+
this.heap[idx],
49+
this.heap[smallest],
50+
];
51+
idx = smallest;
52+
}
53+
}
54+
}
55+
56+
class MaxHeap {
57+
heap: number[] = [];
58+
size(): number {
59+
return this.heap.length;
60+
}
61+
peek(): number | null {
62+
return this.heap[0] ?? null;
63+
}
64+
push(val: number) {
65+
this.heap.push(val);
66+
this.bubbleUp(this.size() - 1);
67+
}
68+
pop(): number | null {
69+
if (this.size() === 0) return null;
70+
const top = this.heap[0];
71+
const end = this.heap.pop()!;
72+
if (this.size() > 0) {
73+
this.heap[0] = end;
74+
this.bubbleDown(0);
75+
}
76+
return top;
77+
}
78+
private bubbleUp(idx: number) {
79+
while (idx > 0) {
80+
const parent = Math.floor((idx - 1) / 2);
81+
if (this.heap[parent] >= this.heap[idx]) break;
82+
[this.heap[parent], this.heap[idx]] = [this.heap[idx], this.heap[parent]];
83+
idx = parent;
84+
}
85+
}
86+
private bubbleDown(idx: number) {
87+
const n = this.size();
88+
while (true) {
89+
let left = idx * 2 + 1;
90+
let right = idx * 2 + 2;
91+
let largest = idx;
92+
if (left < n && this.heap[left] > this.heap[largest]) largest = left;
93+
if (right < n && this.heap[right] > this.heap[largest]) largest = right;
94+
if (largest === idx) break;
95+
[this.heap[largest], this.heap[idx]] = [
96+
this.heap[idx],
97+
this.heap[largest],
98+
];
99+
idx = largest;
100+
}
101+
}
102+
}
103+
104+
class MedianFinder {
105+
private minH = new MinHeap();
106+
private maxH = new MaxHeap();
107+
108+
addNum(num: number): void {
109+
if (this.maxH.size() === 0 || num <= (this.maxH.peek() ?? num)) {
110+
this.maxH.push(num);
111+
} else {
112+
this.minH.push(num);
113+
}
114+
115+
// Rebalance
116+
if (this.maxH.size() > this.minH.size() + 1) {
117+
this.minH.push(this.maxH.pop()!);
118+
} else if (this.minH.size() > this.maxH.size()) {
119+
this.maxH.push(this.minH.pop()!);
120+
}
121+
}
122+
123+
findMedian(): number {
124+
const total = this.maxH.size() + this.minH.size();
125+
if (total % 2 === 1) {
126+
return this.maxH.peek()!;
127+
} else {
128+
return (this.maxH.peek()! + this.minH.peek()!) / 2;
129+
}
130+
}
131+
}

0 commit comments

Comments
 (0)