Skip to content

Commit 455bf00

Browse files
committed
feat(js): add OOP modular solution and documentation for normal challenge 10 - Top K Frequent Elements
1 parent f94b6bf commit 455bf00

File tree

11 files changed

+352
-93
lines changed

11 files changed

+352
-93
lines changed
Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
# Challenge Description and Solution
2+
3+
## English Version
4+
5+
### Challenge Description
6+
Given an array of integers, return the k most frequent elements. Use a class `TopKFrequent` that encapsulates the logic for counting frequencies and maintaining a min heap to find the top k frequent elements.
7+
8+
### Code Explanation
9+
The solution uses a class `TopKFrequent` that encapsulates the logic for counting frequencies and maintaining a min heap to find the top k frequent elements.
10+
11+
The class builds a frequency map from the input array, then uses heap operations (`heapifyUp` and `heapifyDown`) to maintain a min heap of size k.
12+
13+
### Relevant Code Snippet
14+
15+
```javascript
16+
class TopKFrequent {
17+
constructor(nums, k) {
18+
this.nums = nums;
19+
this.k = k;
20+
this.frequencyMap = new Map();
21+
this.heap = [];
22+
}
23+
24+
swap(i, j) {
25+
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
26+
}
27+
28+
heapifyUp(index) {
29+
let parent = Math.floor((index - 1) / 2);
30+
while (index > 0 && this.heap[index][1] < this.heap[parent][1]) {
31+
this.swap(index, parent);
32+
index = parent;
33+
parent = Math.floor((index - 1) / 2);
34+
}
35+
}
36+
37+
heapifyDown(index) {
38+
const length = this.heap.length;
39+
let smallest = index;
40+
const left = 2 * index + 1;
41+
const right = 2 * index + 2;
42+
43+
if (left < length && this.heap[left][1] < this.heap[smallest][1]) {
44+
smallest = left;
45+
}
46+
if (right < length && this.heap[right][1] < this.heap[smallest][1]) {
47+
smallest = right;
48+
}
49+
if (smallest !== index) {
50+
this.swap(index, smallest);
51+
this.heapifyDown(smallest);
52+
}
53+
}
54+
55+
buildFrequencyMap() {
56+
for (const num of this.nums) {
57+
this.frequencyMap.set(num, (this.frequencyMap.get(num) || 0) + 1);
58+
}
59+
}
60+
61+
findTopK() {
62+
this.buildFrequencyMap();
63+
64+
for (const [num, freq] of this.frequencyMap.entries()) {
65+
this.heap.push([num, freq]);
66+
this.heapifyUp(this.heap.length - 1);
67+
if (this.heap.length > this.k) {
68+
this.heap[0] = this.heap.pop();
69+
this.heapifyDown(0);
70+
}
71+
}
72+
73+
return this.heap.map(item => item[0]);
74+
}
75+
}
76+
```
77+
78+
### Example Usage
79+
80+
```javascript
81+
import TopKFrequent from './topKFrequent.js';
82+
83+
const nums = [1, 1, 1, 2, 2, 3];
84+
const k = 2;
85+
const topK = new TopKFrequent(nums, k);
86+
const result = topK.findTopK();
87+
console.log('Top k frequent elements:', result);
88+
```
89+
90+
---
91+
92+
## Versión en Español
93+
94+
### Descripción del Reto
95+
Dado un arreglo de enteros, devuelve los k elementos más frecuentes. Usa una clase `TopKFrequent` que encapsula la lógica para contar frecuencias y mantener un heap mínimo para encontrar los k elementos más frecuentes.
96+
97+
### Explicación del Código
98+
La solución usa una clase `TopKFrequent` que encapsula la lógica para contar frecuencias y mantener un heap mínimo para encontrar los k elementos más frecuentes.
99+
100+
La clase construye un mapa de frecuencias a partir del arreglo de entrada, luego usa operaciones de heap (`heapifyUp` y `heapifyDown`) para mantener un heap mínimo de tamaño k.
101+
102+
### Fragmento de Código Relevante
103+
104+
```javascript
105+
class TopKFrequent {
106+
constructor(nums, k) {
107+
this.nums = nums;
108+
this.k = k;
109+
this.frequencyMap = new Map();
110+
this.heap = [];
111+
}
112+
113+
swap(i, j) {
114+
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
115+
}
116+
117+
heapifyUp(index) {
118+
let parent = Math.floor((index - 1) / 2);
119+
while (index > 0 && this.heap[index][1] < this.heap[parent][1]) {
120+
this.swap(index, parent);
121+
index = parent;
122+
parent = Math.floor((index - 1) / 2);
123+
}
124+
}
125+
126+
heapifyDown(index) {
127+
const length = this.heap.length;
128+
let smallest = index;
129+
const left = 2 * index + 1;
130+
const right = 2 * index + 2;
131+
132+
if (left < length && this.heap[left][1] < this.heap[smallest][1]) {
133+
smallest = left;
134+
}
135+
if (right < length && this.heap[right][1] < this.heap[smallest][1]) {
136+
smallest = right;
137+
}
138+
if (smallest !== index) {
139+
this.swap(index, smallest);
140+
this.heapifyDown(smallest);
141+
}
142+
}
143+
144+
buildFrequencyMap() {
145+
for (const num of this.nums) {
146+
this.frequencyMap.set(num, (this.frequencyMap.get(num) || 0) + 1);
147+
}
148+
}
149+
150+
findTopK() {
151+
this.buildFrequencyMap();
152+
153+
for (const [num, freq] of this.frequencyMap.entries()) {
154+
this.heap.push([num, freq]);
155+
this.heapifyUp(this.heap.length - 1);
156+
if (this.heap.length > this.k) {
157+
this.heap[0] = this.heap.pop();
158+
this.heapifyDown(0);
159+
}
160+
}
161+
162+
return this.heap.map(item => item[0]);
163+
}
164+
}
165+
```
166+
167+
### Ejemplo de Uso
168+
169+
```javascript
170+
import TopKFrequent from './topKFrequent.js';
171+
172+
const nums = [1, 1, 1, 2, 2, 3];
173+
const k = 2;
174+
const topK = new TopKFrequent(nums, k);
175+
const result = topK.findTopK();
176+
console.log('Elementos más frecuentes:', result);
177+
```
178+
console.log('Elementos más frecuentes:', result);
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import TopKFrequent from './topKFrequent.js';
2+
3+
/*
4+
Challenge: Given an array of integers, return the k most frequent elements. Use a hashmap and a heap to optimize the solution.
5+
*/
6+
7+
function main() {
8+
const nums = [1, 1, 1, 2, 2, 3];
9+
const k = 2;
10+
const topK = new TopKFrequent(nums, k);
11+
const result = topK.findTopK();
12+
console.log('Top k frequent elements:', result);
13+
}
14+
15+
main();
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// topKFrequent.js - Class-based solution to find the top k frequent elements using hashmap and heap
2+
3+
class TopKFrequent {
4+
constructor(nums, k) {
5+
this.nums = nums;
6+
this.k = k;
7+
this.frequencyMap = new Map();
8+
this.heap = [];
9+
}
10+
11+
swap(i, j) {
12+
[this.heap[i], this.heap[j]] = [this.heap[j], this.heap[i]];
13+
}
14+
15+
heapifyUp(index) {
16+
let parent = Math.floor((index - 1) / 2);
17+
while (index > 0 && this.heap[index][1] < this.heap[parent][1]) {
18+
this.swap(index, parent);
19+
index = parent;
20+
parent = Math.floor((index - 1) / 2);
21+
}
22+
}
23+
24+
heapifyDown(index) {
25+
const length = this.heap.length;
26+
let smallest = index;
27+
const left = 2 * index + 1;
28+
const right = 2 * index + 2;
29+
30+
if (left < length && this.heap[left][1] < this.heap[smallest][1]) {
31+
smallest = left;
32+
}
33+
if (right < length && this.heap[right][1] < this.heap[smallest][1]) {
34+
smallest = right;
35+
}
36+
if (smallest !== index) {
37+
this.swap(index, smallest);
38+
this.heapifyDown(smallest);
39+
}
40+
}
41+
42+
buildFrequencyMap() {
43+
for (const num of this.nums) {
44+
this.frequencyMap.set(num, (this.frequencyMap.get(num) || 0) + 1);
45+
}
46+
}
47+
48+
findTopK() {
49+
this.buildFrequencyMap();
50+
51+
for (const [num, freq] of this.frequencyMap.entries()) {
52+
this.heap.push([num, freq]);
53+
this.heapifyUp(this.heap.length - 1);
54+
if (this.heap.length > this.k) {
55+
this.heap[0] = this.heap.pop();
56+
this.heapifyDown(0);
57+
}
58+
}
59+
60+
return this.heap.map(item => item[0]);
61+
}
62+
}
63+
64+
export default TopKFrequent;
Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,28 @@
1-
// intervals.js - Merge overlapping intervals
1+
// intervals.js - Merge overlapping intervals using OOP
22

3-
function mergeIntervals(intervals) {
4-
if (!intervals || intervals.length === 0) {
5-
return [];
6-
}
3+
class Intervals {
4+
static mergeIntervals(intervals) {
5+
if (!intervals || intervals.length === 0) {
6+
return [];
7+
}
78

8-
// Sort intervals based on the start time
9-
intervals.sort((a, b) => a[0] - b[0]);
10-
const merged = [intervals[0]];
9+
// Sort intervals based on the start time
10+
intervals.sort((a, b) => a[0] - b[0]);
11+
const merged = [intervals[0]];
1112

12-
for (let i = 1; i < intervals.length; i++) {
13-
const current = intervals[i];
14-
const last = merged[merged.length - 1];
13+
for (let i = 1; i < intervals.length; i++) {
14+
const current = intervals[i];
15+
const last = merged[merged.length - 1];
1516

16-
if (current[0] <= last[1]) { // Overlapping intervals
17-
merged[merged.length - 1] = [last[0], Math.max(last[1], current[1])];
18-
} else {
19-
merged.push(current);
17+
if (current[0] <= last[1]) { // Overlapping intervals
18+
merged[merged.length - 1] = [last[0], Math.max(last[1], current[1])];
19+
} else {
20+
merged.push(current);
21+
}
2022
}
21-
}
2223

23-
return merged;
24+
return merged;
25+
}
2426
}
2527

26-
export default mergeIntervals;
28+
export default Intervals;

2-NORMAL/JavaScript/6-merge-overlapping-intervals/proposed-solution/main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
1-
// main.js - Example usage of mergeIntervals function
1+
// main.js - Example usage of Intervals class
22

3-
import mergeIntervals from './intervals.js';
3+
import Intervals from './intervals.js';
44

55
/*
66
Challenge: Given a list of intervals (e.g., [[1, 3], [2, 6], [8, 10]]), implement a function that merges all overlapping intervals and returns an array with the resulting intervals.
77
*/
88

99
function main() {
1010
const intervals = [[1, 3], [2, 6], [8, 10], [15, 18]];
11-
const merged = mergeIntervals(intervals);
11+
const merged = Intervals.mergeIntervals(intervals);
1212
console.log('Merged intervals:', merged);
1313
}
1414

2-NORMAL/JavaScript/7-validate-parentheses/proposed-solution/main.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// main.js - Example usage of isValidParentheses function
1+
// main.js - Example usage of ParenthesesValidator class
22

3-
import isValidParentheses from './parentheses.js';
3+
import ParenthesesValidator from './parentheses.js';
44

55
/*
66
Challenge: Create a function that, given a string composed of parentheses and possibly other opening and closing symbols, verifies if the sequence is valid (i.e., each open symbol has its corresponding closing symbol in the correct order). Use a stack data structure to solve it.
@@ -9,7 +9,7 @@ Challenge: Create a function that, given a string composed of parentheses and po
99
function main() {
1010
const testStrings = ["()", "()[]{}", "(]", "([)]", "{[]}"];
1111
testStrings.forEach(s => {
12-
console.log(`Is '${s}' valid?`, isValidParentheses(s));
12+
console.log(`Is '${s}' valid?`, ParenthesesValidator.isValidParentheses(s));
1313
});
1414
}
1515

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
1-
// parentheses.js - Validate parentheses and other symbols using a stack
1+
class ParenthesesValidator {
2+
static isValidParentheses(s) {
3+
const stack = [];
4+
const mapping = { ')': '(', ']': '[', '}': '{' };
25

3-
function isValidParentheses(s) {
4-
const stack = [];
5-
const mapping = { ')': '(', ']': '[', '}': '{' };
6-
7-
for (const char of s) {
8-
if (Object.values(mapping).includes(char)) {
9-
stack.push(char);
10-
} else if (char in mapping) {
11-
if (stack.length === 0 || stack.pop() !== mapping[char]) {
12-
return false;
6+
for (const char of s) {
7+
if (Object.values(mapping).includes(char)) {
8+
stack.push(char);
9+
} else if (char in mapping) {
10+
if (stack.length === 0 || stack.pop() !== mapping[char]) {
11+
return false;
12+
}
13+
} else {
14+
// Ignore other characters
15+
continue;
1316
}
14-
} else {
15-
// Ignore other characters
16-
continue;
1717
}
18-
}
1918

20-
return stack.length === 0;
19+
return stack.length === 0;
20+
}
2121
}
2222

23-
export default isValidParentheses;
23+
export default ParenthesesValidator;

0 commit comments

Comments
 (0)