|
1 | 1 | // #Hard #Top_100_Liked_Questions #Top_Interview_Questions #Sorting #Two_Pointers #Design
|
2 | 2 | // #Heap_Priority_Queue #Data_Stream #Big_O_Time_O(n*log_n)_Space_O(n)
|
3 |
| -// #2023_10_06_Time_426_ms_(85.33%)_Space_98.1_MB_(48.67%) |
| 3 | +// #2023_10_13_Time_335_ms_(99.44%)_Space_96.8_MB_(69.49%) |
4 | 4 |
|
5 |
| -class MaxHeap<T> { |
6 |
| - private heap: T[] |
| 5 | +class Heap { |
| 6 | + private heap: number[] |
7 | 7 |
|
8 | 8 | constructor() {
|
9 |
| - this.heap = [] |
| 9 | + this.heap = [0] |
10 | 10 | }
|
11 | 11 |
|
12 |
| - size(): number { |
13 |
| - return this.heap.length |
| 12 | + peek(): number | null { |
| 13 | + return this.heap[1] ?? null |
14 | 14 | }
|
15 | 15 |
|
16 |
| - isEmpty(): boolean { |
17 |
| - return this.heap.length === 0 |
18 |
| - } |
19 |
| - |
20 |
| - peek(): T { |
21 |
| - return this.heap[0] |
22 |
| - } |
23 |
| - |
24 |
| - add(value: T): void { |
25 |
| - this.heap.push(value) |
26 |
| - this.heapifyUp() |
27 |
| - } |
28 |
| - |
29 |
| - poll(): T { |
30 |
| - const max = this.heap[0] |
31 |
| - const last = this.heap.pop() |
32 |
| - if (this.heap.length > 0) { |
33 |
| - this.heap[0] = last |
34 |
| - this.heapifyDown() |
35 |
| - } |
36 |
| - return max |
37 |
| - } |
38 |
| - |
39 |
| - private heapifyUp(): void { |
40 |
| - let currentIndex = this.heap.length - 1 |
41 |
| - while (this.hasParent(currentIndex) && this.parent(currentIndex) < this.heap[currentIndex]) { |
42 |
| - const parentIndex = this.getParentIndex(currentIndex) |
43 |
| - this.swap(parentIndex, currentIndex) |
44 |
| - currentIndex = parentIndex |
45 |
| - } |
46 |
| - } |
47 |
| - |
48 |
| - private heapifyDown(): void { |
49 |
| - let currentIndex = 0 |
50 |
| - while (this.hasLeftChild(currentIndex)) { |
51 |
| - let biggerChildIndex = this.getLeftChildIndex(currentIndex) |
52 |
| - if (this.hasRightChild(currentIndex) && this.rightChild(currentIndex) > this.leftChild(currentIndex)) { |
53 |
| - biggerChildIndex = this.getRightChildIndex(currentIndex) |
54 |
| - } |
55 |
| - |
56 |
| - if (this.heap[currentIndex] > this.heap[biggerChildIndex]) { |
57 |
| - break |
58 |
| - } |
59 |
| - |
60 |
| - this.swap(currentIndex, biggerChildIndex) |
61 |
| - currentIndex = biggerChildIndex |
| 16 | + push(val: number): void { |
| 17 | + this.heap.push(val) |
| 18 | + let i = this.heap.length - 1 |
| 19 | + let parI = Math.floor(i / 2) |
| 20 | + while (i > 1 && this.heap[i] < this.heap[parI]) { |
| 21 | + const tmp = this.heap[i] |
| 22 | + this.heap[i] = this.heap[parI] |
| 23 | + this.heap[parI] = tmp |
| 24 | + i = parI |
| 25 | + parI = Math.floor(i / 2) |
62 | 26 | }
|
63 | 27 | }
|
64 | 28 |
|
65 |
| - private hasParent(index: number): boolean { |
66 |
| - return this.getParentIndex(index) >= 0 |
67 |
| - } |
68 |
| - |
69 |
| - private hasLeftChild(index: number): boolean { |
70 |
| - return this.getLeftChildIndex(index) < this.heap.length |
71 |
| - } |
72 |
| - |
73 |
| - private hasRightChild(index: number): boolean { |
74 |
| - return this.getRightChildIndex(index) < this.heap.length |
75 |
| - } |
76 |
| - |
77 |
| - private parent(index: number): T { |
78 |
| - return this.heap[this.getParentIndex(index)] |
79 |
| - } |
80 |
| - |
81 |
| - private leftChild(index: number): T { |
82 |
| - return this.heap[this.getLeftChildIndex(index)] |
83 |
| - } |
84 |
| - |
85 |
| - private rightChild(index: number): T { |
86 |
| - return this.heap[this.getRightChildIndex(index)] |
87 |
| - } |
88 |
| - |
89 |
| - private getParentIndex(index: number): number { |
90 |
| - return Math.floor((index - 1) / 2) |
91 |
| - } |
92 |
| - |
93 |
| - private getLeftChildIndex(index: number): number { |
94 |
| - return index * 2 + 1 |
95 |
| - } |
96 |
| - |
97 |
| - private getRightChildIndex(index: number): number { |
98 |
| - return index * 2 + 2 |
99 |
| - } |
100 |
| - |
101 |
| - private swap(index1: number, index2: number): void { |
102 |
| - const temp = this.heap[index1] |
103 |
| - this.heap[index1] = this.heap[index2] |
104 |
| - this.heap[index2] = temp |
105 |
| - } |
106 |
| -} |
107 |
| - |
108 |
| -class MinHeap<T> { |
109 |
| - private heap: T[] |
110 |
| - |
111 |
| - constructor() { |
112 |
| - this.heap = [] |
113 |
| - } |
114 |
| - |
115 |
| - size(): number { |
116 |
| - return this.heap.length |
117 |
| - } |
118 |
| - |
119 |
| - isEmpty(): boolean { |
120 |
| - return this.heap.length === 0 |
121 |
| - } |
122 |
| - |
123 |
| - peek(): T { |
124 |
| - return this.heap[0] |
125 |
| - } |
126 |
| - |
127 |
| - add(value: T): void { |
128 |
| - this.heap.push(value) |
129 |
| - this.heapifyUp() |
130 |
| - } |
131 |
| - |
132 |
| - poll(): T { |
133 |
| - const min = this.heap[0] |
134 |
| - const last = this.heap.pop() |
135 |
| - if (this.heap.length > 0) { |
136 |
| - this.heap[0] = last |
137 |
| - this.heapifyDown() |
| 29 | + pop(): number | null { |
| 30 | + if (this.heap.length == 1) { |
| 31 | + return null |
138 | 32 | }
|
139 |
| - return min |
140 |
| - } |
141 |
| - |
142 |
| - private heapifyUp(): void { |
143 |
| - let currentIndex = this.heap.length - 1 |
144 |
| - while (this.hasParent(currentIndex) && this.parent(currentIndex) > this.heap[currentIndex]) { |
145 |
| - const parentIndex = this.getParentIndex(currentIndex) |
146 |
| - this.swap(parentIndex, currentIndex) |
147 |
| - currentIndex = parentIndex |
| 33 | + if (this.heap.length == 2) { |
| 34 | + return this.heap.pop() |
148 | 35 | }
|
149 |
| - } |
150 |
| - |
151 |
| - private heapifyDown(): void { |
152 |
| - let currentIndex = 0 |
153 |
| - while (this.hasLeftChild(currentIndex)) { |
154 |
| - let smallerChildIndex = this.getLeftChildIndex(currentIndex) |
155 |
| - if (this.hasRightChild(currentIndex) && this.rightChild(currentIndex) < this.leftChild(currentIndex)) { |
156 |
| - smallerChildIndex = this.getRightChildIndex(currentIndex) |
157 |
| - } |
158 |
| - |
159 |
| - if (this.heap[currentIndex] < this.heap[smallerChildIndex]) { |
| 36 | + const res = this.heap[1] |
| 37 | + this.heap[1] = this.heap.pop() |
| 38 | + let i = 1 |
| 39 | + while (2 * i < this.heap.length) { |
| 40 | + const leftChildIdx = 2 * i |
| 41 | + const rightChildIdx = 2 * i + 1 |
| 42 | + if ( |
| 43 | + rightChildIdx < this.heap.length && |
| 44 | + this.heap[rightChildIdx] < this.heap[leftChildIdx] && |
| 45 | + this.heap[i] > this.heap[rightChildIdx] |
| 46 | + ) { |
| 47 | + const tmp = this.heap[i] |
| 48 | + this.heap[i] = this.heap[rightChildIdx] |
| 49 | + this.heap[rightChildIdx] = tmp |
| 50 | + i = rightChildIdx |
| 51 | + } else if (this.heap[i] > this.heap[leftChildIdx]) { |
| 52 | + const tmp = this.heap[i] |
| 53 | + this.heap[i] = this.heap[leftChildIdx] |
| 54 | + this.heap[leftChildIdx] = tmp |
| 55 | + i = leftChildIdx |
| 56 | + } else { |
160 | 57 | break
|
161 | 58 | }
|
162 |
| - |
163 |
| - this.swap(currentIndex, smallerChildIndex) |
164 |
| - currentIndex = smallerChildIndex |
165 | 59 | }
|
| 60 | + return res |
166 | 61 | }
|
167 | 62 |
|
168 |
| - private hasParent(index: number): boolean { |
169 |
| - return this.getParentIndex(index) >= 0 |
170 |
| - } |
171 |
| - |
172 |
| - private hasLeftChild(index: number): boolean { |
173 |
| - return this.getLeftChildIndex(index) < this.heap.length |
174 |
| - } |
175 |
| - |
176 |
| - private hasRightChild(index: number): boolean { |
177 |
| - return this.getRightChildIndex(index) < this.heap.length |
178 |
| - } |
179 |
| - |
180 |
| - private parent(index: number): T { |
181 |
| - return this.heap[this.getParentIndex(index)] |
182 |
| - } |
183 |
| - |
184 |
| - private leftChild(index: number): T { |
185 |
| - return this.heap[this.getLeftChildIndex(index)] |
186 |
| - } |
187 |
| - |
188 |
| - private rightChild(index: number): T { |
189 |
| - return this.heap[this.getRightChildIndex(index)] |
190 |
| - } |
191 |
| - |
192 |
| - private getParentIndex(index: number): number { |
193 |
| - return Math.floor((index - 1) / 2) |
194 |
| - } |
195 |
| - |
196 |
| - private getLeftChildIndex(index: number): number { |
197 |
| - return index * 2 + 1 |
198 |
| - } |
199 |
| - |
200 |
| - private getRightChildIndex(index: number): number { |
201 |
| - return index * 2 + 2 |
202 |
| - } |
203 |
| - |
204 |
| - private swap(index1: number, index2: number): void { //NOSONAR |
205 |
| - const temp = this.heap[index1] |
206 |
| - this.heap[index1] = this.heap[index2] |
207 |
| - this.heap[index2] = temp |
| 63 | + length(): number { |
| 64 | + return this.heap.length - 1 |
208 | 65 | }
|
209 | 66 | }
|
210 | 67 |
|
211 | 68 | class MedianFinder {
|
212 |
| - private maxHeap: MaxHeap<number> |
213 |
| - private minHeap: MinHeap<number> |
| 69 | + large: Heap |
| 70 | + small: Heap |
214 | 71 |
|
215 | 72 | constructor() {
|
216 |
| - this.maxHeap = new MaxHeap<number>() |
217 |
| - this.minHeap = new MinHeap<number>() |
| 73 | + this.large = new Heap() |
| 74 | + this.small = new Heap() |
218 | 75 | }
|
219 | 76 |
|
220 | 77 | addNum(num: number): void {
|
221 |
| - if (this.maxHeap.isEmpty() || num <= this.maxHeap.peek()) { |
222 |
| - this.maxHeap.add(num) |
| 78 | + if (this.small.length() === this.large.length()) { |
| 79 | + this.small.push(-num) |
| 80 | + this.large.push(-this.small.pop()) |
223 | 81 | } else {
|
224 |
| - this.minHeap.add(num) |
225 |
| - } |
226 |
| - |
227 |
| - if (this.maxHeap.size() - this.minHeap.size() > 1) { |
228 |
| - this.minHeap.add(this.maxHeap.poll()) |
229 |
| - } else if (this.minHeap.size() > this.maxHeap.size()) { |
230 |
| - this.maxHeap.add(this.minHeap.poll()) |
| 82 | + this.large.push(num) |
| 83 | + this.small.push(-this.large.pop()) |
231 | 84 | }
|
232 | 85 | }
|
233 | 86 |
|
234 | 87 | findMedian(): number {
|
235 |
| - if (this.maxHeap.size() === this.minHeap.size()) { |
236 |
| - return (this.maxHeap.peek() + this.minHeap.peek()) / 2 |
237 |
| - } else { |
238 |
| - return this.maxHeap.size() > this.minHeap.size() ? this.maxHeap.peek() : this.minHeap.peek() |
| 88 | + if (this.small.length() === this.large.length()) { |
| 89 | + return (this.large.peek() - this.small.peek()) / 2 |
239 | 90 | }
|
| 91 | + return this.large.peek() |
240 | 92 | }
|
241 | 93 | }
|
242 | 94 |
|
|
0 commit comments