Skip to content

Commit 778edbb

Browse files
Jeehay28Jeehay28
authored andcommitted
Add find-median-from-data-stream solution in TS
1 parent 7efbae4 commit 778edbb

File tree

1 file changed

+194
-0
lines changed

1 file changed

+194
-0
lines changed
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
class MedianFinder {
2+
// [1, 2, 3, 4, 5, 6]
3+
private lower: MaxHeap; // max heap [3, 2, 1]
4+
private upper: MinHeap; // min heap [4, 5, 6]
5+
6+
constructor() {
7+
this.upper = new MinHeap();
8+
this.lower = new MaxHeap();
9+
}
10+
11+
// TC: O(log n)
12+
// SC: O(n)
13+
addNum(num: number): void {
14+
if (this.upper.size() === 0 || this.upper.getRoot() <= num) {
15+
this.upper.insert(num);
16+
} else {
17+
this.lower.insert(num);
18+
}
19+
20+
// Balance
21+
if (this.lower.size() - this.upper.size() > 1) {
22+
this.upper.insert(this.lower.removeRoot());
23+
} else if (this.upper.size() - this.lower.size() > 1) {
24+
this.lower.insert(this.upper.removeRoot());
25+
}
26+
}
27+
28+
// TC: O(1)
29+
// SC: O(1)
30+
findMedian(): number {
31+
if (this.upper.size() === this.lower.size()) {
32+
return (this.upper.getRoot() + this.lower.getRoot()) / 2;
33+
} else if (this.upper.size() > this.lower.size()) {
34+
return this.upper.getRoot();
35+
} else {
36+
return this.lower.getRoot();
37+
}
38+
}
39+
}
40+
41+
/**
42+
* Your MedianFinder object will be instantiated and called as such:
43+
* var obj = new MedianFinder()
44+
* obj.addNum(num)
45+
* var param_2 = obj.findMedian()
46+
*/
47+
48+
class MinHeap {
49+
private heap: number[] = [];
50+
51+
size(): number {
52+
return this.heap.length;
53+
}
54+
55+
getRoot(): number {
56+
return this.heap[0];
57+
}
58+
59+
insert(num: number): void {
60+
this.heap.push(num);
61+
this.bubbleUp();
62+
}
63+
64+
removeRoot(): number {
65+
const top = this.heap[0];
66+
const end = this.heap.pop()!;
67+
68+
if (this.heap.length > 0) {
69+
this.heap[0] = end;
70+
this.bubbleDown();
71+
}
72+
73+
return top;
74+
}
75+
76+
// Fix after removal (downward)
77+
bubbleDown(): void {
78+
let idx = 0;
79+
const length = this.heap.length;
80+
const val = this.heap[0];
81+
82+
while (true) {
83+
let leftIdx = 2 * idx + 1;
84+
let rightIdx = 2 * idx + 2;
85+
let swap = idx;
86+
87+
if (leftIdx < length && this.heap[leftIdx] < this.heap[swap]) {
88+
swap = leftIdx;
89+
}
90+
91+
if (rightIdx < length && this.heap[rightIdx] < this.heap[swap]) {
92+
swap = rightIdx;
93+
}
94+
95+
if (swap === idx) break;
96+
97+
this.heap[idx] = this.heap[swap];
98+
this.heap[swap] = val;
99+
idx = swap;
100+
}
101+
}
102+
103+
// Fix after insert (upward)
104+
bubbleUp(): void {
105+
let idx = this.heap.length - 1;
106+
const val = this.heap[idx];
107+
// Heap as an array
108+
// left child: 2 * i + 1
109+
// right child: 2 * i + 2
110+
// parent: Math.floor((i-1) / 2)
111+
112+
while (idx > 0) {
113+
const parentIdx = Math.floor((idx - 1) / 2);
114+
const parent = this.heap[parentIdx];
115+
116+
if (val >= parent) break;
117+
118+
this.heap[parentIdx] = val;
119+
this.heap[idx] = parent;
120+
idx = parentIdx;
121+
}
122+
}
123+
}
124+
125+
class MaxHeap {
126+
private heap: number[] = [];
127+
128+
size(): number {
129+
return this.heap.length;
130+
}
131+
132+
getRoot(): number {
133+
return this.heap[0];
134+
}
135+
136+
insert(num: number): void {
137+
this.heap.push(num);
138+
this.bubbleUp();
139+
}
140+
141+
removeRoot(): number {
142+
const top = this.heap[0];
143+
const end = this.heap.pop()!;
144+
145+
if (this.heap.length > 0) {
146+
this.heap[0] = end;
147+
this.bubbleDown();
148+
}
149+
150+
return top;
151+
}
152+
153+
bubbleDown(): void {
154+
let idx = 0;
155+
const length = this.heap.length;
156+
const val = this.heap[0];
157+
158+
while (true) {
159+
let leftIdx = 2 * idx + 1;
160+
let rightIdx = 2 * idx + 2;
161+
let swap = idx;
162+
163+
if (leftIdx < length && this.heap[leftIdx] > this.heap[swap]) {
164+
swap = leftIdx;
165+
}
166+
167+
if (rightIdx < length && this.heap[rightIdx] > this.heap[swap]) {
168+
swap = rightIdx;
169+
}
170+
171+
if (swap === idx) break;
172+
173+
this.heap[idx] = this.heap[swap];
174+
this.heap[swap] = val;
175+
idx = swap;
176+
}
177+
}
178+
179+
bubbleUp(): void {
180+
let idx = this.heap.length - 1;
181+
const val = this.heap[idx];
182+
183+
while (idx > 0) {
184+
const parentIdx = Math.floor((idx - 1) / 2);
185+
const parent = this.heap[parentIdx];
186+
187+
if (val <= parent) break;
188+
189+
this.heap[parentIdx] = val;
190+
this.heap[idx] = parent;
191+
idx = parentIdx;
192+
}
193+
}
194+
}

0 commit comments

Comments
 (0)