Skip to content

Commit 245aa4c

Browse files
authored
Merge branch 'DaleStudy:main' into main
2 parents 21d8ac7 + a68c8a4 commit 245aa4c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+2869
-58
lines changed
Lines changed: 127 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,127 @@
1+
/**
2+
* [Problem]: [295] Find Median from Data Stream
3+
* (https://leetcode.com/problems/find-median-from-data-stream/description/)
4+
*/
5+
class Heap {
6+
private numbers: number[];
7+
private compare: (a: number, b: number) => boolean;
8+
9+
constructor(compare: (a: number, b: number) => boolean) {
10+
this.numbers = [];
11+
this.compare = compare;
12+
}
13+
14+
private getParentIdx(index: number) {
15+
return Math.floor((index - 1) / 2);
16+
}
17+
18+
private getLeftChildIdx(index: number) {
19+
return 2 * index + 1;
20+
}
21+
22+
private getRightChildIdx(index: number) {
23+
return 2 * index + 2;
24+
}
25+
26+
private swap(index1: number, index2: number): void {
27+
[this.numbers[index1], this.numbers[index2]] = [this.numbers[index2], this.numbers[index1]];
28+
}
29+
30+
private heapifyUp(index: number) {
31+
const parentIndex = this.getParentIdx(index);
32+
if (0 <= parentIndex && this.compare(this.numbers[index], this.numbers[parentIndex])) {
33+
this.swap(index, parentIndex);
34+
this.heapifyUp(parentIndex);
35+
}
36+
}
37+
38+
private heapifyDown(index: number): void {
39+
const leftChildIndex = this.getLeftChildIdx(index);
40+
const rightChildIndex = this.getRightChildIdx(index);
41+
let largestIndex = index;
42+
43+
if (
44+
leftChildIndex < this.numbers.length &&
45+
this.compare(this.numbers[leftChildIndex], this.numbers[largestIndex])
46+
) {
47+
largestIndex = leftChildIndex;
48+
}
49+
50+
if (
51+
rightChildIndex < this.numbers.length &&
52+
this.compare(this.numbers[rightChildIndex], this.numbers[largestIndex])
53+
) {
54+
largestIndex = rightChildIndex;
55+
}
56+
57+
if (largestIndex !== index) {
58+
this.swap(index, largestIndex);
59+
this.heapifyDown(largestIndex);
60+
}
61+
}
62+
63+
insert(number: number) {
64+
this.numbers.push(number);
65+
this.heapifyUp(this.numbers.length - 1);
66+
}
67+
68+
pop() {
69+
if (this.numbers.length === 0) {
70+
return null;
71+
}
72+
73+
if (this.numbers.length === 1) {
74+
return this.numbers.pop()!;
75+
}
76+
77+
const root = this.numbers[0];
78+
this.numbers[0] = this.numbers.pop()!;
79+
this.heapifyDown(0);
80+
81+
return root;
82+
}
83+
84+
peek() {
85+
return this.numbers.length > 0 ? this.numbers[0] : null;
86+
}
87+
88+
size(): number {
89+
return this.numbers.length;
90+
}
91+
}
92+
93+
class MedianFinder {
94+
private smallHeap: Heap;
95+
private largeHeap: Heap;
96+
97+
constructor() {
98+
this.smallHeap = new Heap((a, b) => a > b);
99+
this.largeHeap = new Heap((a, b) => a < b);
100+
}
101+
102+
//μ‹œκ°„λ³΅μž‘λ„ O(log n)
103+
addNum(num: number): void {
104+
this.smallHeap.insert(num);
105+
this.largeHeap.insert(this.smallHeap.pop()!);
106+
107+
if (this.smallHeap.size() < this.largeHeap.size()) {
108+
this.smallHeap.insert(this.largeHeap.pop()!);
109+
}
110+
}
111+
112+
//μ‹œκ°„λ³΅μž‘λ„ O(1)
113+
findMedian(): number {
114+
if (this.smallHeap.size() > this.largeHeap.size()) {
115+
return this.smallHeap.peek()!;
116+
} else {
117+
return (this.smallHeap.peek()! + this.largeHeap.peek()!) / 2;
118+
}
119+
}
120+
}
121+
122+
/**
123+
* Your MedianFinder object will be instantiated and called as such:
124+
* var obj = new MedianFinder()
125+
* obj.addNum(num)
126+
* var param_2 = obj.findMedian()
127+
*/
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+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import heapq
2+
3+
class MedianFinder:
4+
def __init__(self):
5+
self.low = []
6+
self.high = []
7+
def addNum(self, num):
8+
heapq.heappush(self.low, -num)
9+
heapq.heappush(self.high, -heapq.heappop(self.low))
10+
if len(self.high) > len(self.low):
11+
heapq.heappush(self.low, -heapq.heappop(self.high))
12+
def findMedian(self):
13+
if len(self.low) > len(self.high):
14+
return -self.low[0]
15+
return (-self.low[0] + self.high[0]) / 2
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
class MedianFinder:
2+
# Follow up : 두 개의 heap μ‚¬μš©ν•΄μ„œ κ΅¬ν˜„ κ°€λŠ₯(μ‹œκ°„λ³΅μž‘λ„ O(log n), μΆ”κ°€ 곡뢀 ν•„μš”ν•¨)
3+
# heap μ‚¬μš©ν•˜μ§€ μ•Šκ³  이진 탐색 μ‚½μž…μœΌλ‘œ ν’€μ—ˆμŒ
4+
5+
def __init__(self):
6+
# 숫자 μ €μž₯ν•  리슀트 생성
7+
self.arr = []
8+
9+
10+
def addNum(self, num: int) -> None:
11+
# 숫자 μΆ”κ°€ν•˜κ³  μ •λ ¬ν•˜κΈ°
12+
# self.arr.append(num)
13+
# self.arr.sort() -> μ‹œκ°„μ΄ˆκ³Ό(μ‹œκ°„λ³΅μž‘λ„ O(n log n))
14+
# μ΄μ§„νƒμƒ‰μ‚½μž…(μ‹œκ°„λ³΅μž‘λ„ O(n))
15+
bisect.insort(self.arr, num)
16+
17+
def findMedian(self) -> float:
18+
# 길이가 ν™€μˆ˜λ©΄ κ°€μš΄λ° κ°’ 리턴
19+
if len(self.arr)%2 == 1:
20+
return self.arr[len(self.arr)//2]
21+
# 길이가 짝수면 κ°€μš΄λ° 두 수의 평균 리턴
22+
return (self.arr[len(self.arr)//2-1] + self.arr[len(self.arr)//2]) / 2
23+
24+
# Your MedianFinder object will be instantiated and called as such:
25+
# obj = MedianFinder()
26+
# obj.addNum(num)
27+
# param_2 = obj.findMedian()

0 commit comments

Comments
Β (0)