Skip to content

Commit 350180f

Browse files
author
Gonzalo Diaz
committed
[REFACTOR] [Hacker Rank] Interview Preparation Kit: Search: Swap Nodes [Algo]. ESLint manual fixes: no-param-reassign fixed by OOP new solution.
https://eslint.org/docs/latest/rules/no-param-reassign
1 parent b5f110a commit 350180f

File tree

3 files changed

+97
-137
lines changed

3 files changed

+97
-137
lines changed

src/hackerrank/interview_preparation_kit/search/swap_nodes_algo.big.test.ts

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,25 @@
11
import { describe, expect, it } from '@jest/globals';
22

3-
import { Node } from '../../lib/Node';
4-
import { swapNodes, buildTree, flatTree } from './swap_nodes_algo';
3+
import { Tree, swapNodes } from './swap_nodes_algo';
54
import BIG_TEST_CASES from './swap_nodes_algo.big.testcases.json';
65

76
describe('swap_nodes_algo', () => {
87
it('buildTree and plain test cases', () => {
98
expect.assertions(1);
109

1110
BIG_TEST_CASES.forEach((test) => {
12-
const tToTest: Node<number> = buildTree(test.nodes);
13-
const tResult: number[] = flatTree(tToTest);
11+
const tree: Tree = new Tree(test.nodes);
12+
const tresult: number[] = tree.flatTree();
1413

15-
expect(tResult).toStrictEqual(test.flattened);
14+
expect(tresult).toStrictEqual(test.flattened);
1615
});
1716
});
1817

1918
it('swapNodes test cases', () => {
2019
expect.assertions(1);
2120

2221
BIG_TEST_CASES.forEach((test) => {
23-
const tResult: number[][] = swapNodes(test.nodes, test.queries);
22+
const tResult = swapNodes(test.nodes, test.queries);
2423

2524
expect(tResult).toStrictEqual(test.expected);
2625
});

src/hackerrank/interview_preparation_kit/search/swap_nodes_algo.test.ts

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,43 @@
11
import { describe, expect, it } from '@jest/globals';
22

3-
import { buildTree, flatTree, swapNodes } from './swap_nodes_algo';
3+
import { Node } from '../../lib/Node';
4+
import { Tree, swapNodes, __INITIAL_LEVEL__ } from './swap_nodes_algo';
45
import TEST_CASES from './swap_nodes_algo.testcases.json';
56

67
describe('swap_nodes_algo', () => {
78
it('test_buildTree_empty', () => {
8-
expect.assertions(1);
9+
expect.assertions(4);
910

10-
const tInput: number[][] = [];
11-
const tToTest = buildTree(tInput);
12-
const tResult = flatTree(tToTest);
13-
const expected = [1];
11+
const input: number[][] = [];
12+
const tree: Tree = new Tree(input);
13+
const expected: number[] = [1];
1414

15-
expect(tResult).toStrictEqual(expected);
15+
expect(tree.flatTree()).toStrictEqual(expected);
16+
expect(tree.getRoot()).not.toBeNull();
17+
expect(tree.getRoot()).toBeInstanceOf(Node);
18+
expect(tree.getRoot().data).toBe(__INITIAL_LEVEL__);
1619
});
1720

1821
it('test_build_malformed_tree', () => {
19-
expect.assertions(1);
22+
expect.assertions(4);
2023

21-
const tInput: number[][] = [[], []];
22-
const tToTest = buildTree(tInput);
23-
const tResult = flatTree(tToTest);
24-
const expected = [1];
24+
const input: number[][] = [[], []];
25+
const tree: Tree = new Tree(input);
26+
const tresult: number[] = tree.flatTree();
27+
const expected: number[] = [__INITIAL_LEVEL__];
2528

26-
expect(tResult).toStrictEqual(expected);
29+
expect(tresult).toStrictEqual(expected);
30+
expect(tree.getRoot()).not.toBeNull();
31+
expect(tree.getRoot()).toBeInstanceOf(Node);
32+
expect(tree.getRoot().data).toBe(__INITIAL_LEVEL__);
2733
});
2834

2935
it('build tree and flattened tree test cases', () => {
3036
expect.assertions(4);
3137

3238
TEST_CASES.forEach((test) => {
33-
const tToTest = buildTree(test.nodes);
34-
const tResult = flatTree(tToTest);
39+
const tree = new Tree(test.nodes);
40+
const tResult = tree.flatTree();
3541

3642
expect(tResult).toStrictEqual(test.flattened);
3743
});

src/hackerrank/interview_preparation_kit/search/swap_nodes_algo.ts

Lines changed: 71 additions & 116 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
* @link Problem export functioninition [[docs/hackerrank/interview_preparation_kit/search/swap-nodes-algo.md]]
33
*/
44

5-
import { logger as console } from '../../../logger';
65
import { Node } from '../../lib/Node';
76

87
// CONSTANTS
@@ -11,147 +10,104 @@ export const __ROOT_VALUE__: number = 1;
1110
export const __LEAF_VALUE__: number = -1;
1211
const __RADIX__ = 10;
1312

14-
export function callbackCollectNodes(
15-
root: Node<number> | null | undefined,
16-
collect: Record<number, Node<number>[]>,
17-
level: number
18-
): void {
19-
if (root) {
20-
if (collect?.[level] === undefined) {
21-
collect[level] = [root];
22-
} else {
23-
collect[level].push(root);
24-
}
25-
}
26-
}
13+
export class Tree {
14+
root: Node<number>;
2715

28-
export function callbackCollectFlat(
29-
root: Node<number> | null | undefined,
30-
collect: Record<number, Node<number>[]>,
31-
level: number
32-
): void {
33-
const _level: number = 0 * level; // set a unique key to use dict as a list
34-
if (root) {
35-
if (collect?.[_level] === undefined) {
36-
collect[_level] = [root];
37-
} else {
38-
collect[_level].push(root);
39-
}
40-
}
41-
}
16+
nodeCollector: Record<number, Node<number>[]>;
17+
18+
constructor(indexes: number[][]) {
19+
this.root = new Node(__ROOT_VALUE__);
20+
this.nodeCollector = {};
21+
this.nodeCollector[__INITIAL_LEVEL__] = [this.root];
4222

43-
export function traverseInOrderCollector(
44-
root: Node<number> | null | undefined,
45-
collect: Record<number, Node<number>[]>,
46-
level: number,
47-
callbackFn: (
48-
root: Node<number> | null | undefined,
49-
collect: Record<number, Node<number>[]>,
50-
level: number
51-
) => void
52-
): Record<number, Node<number>[]> {
53-
if (root?.left !== null) {
54-
traverseInOrderCollector(root?.left, collect, level + 1, callbackFn);
23+
this.buildTree(indexes);
5524
}
5625

57-
callbackFn(root, collect, level);
26+
buildTree(indexes: number[][]): Tree {
27+
const indexesCopy = [...indexes];
28+
let currentLevel = __INITIAL_LEVEL__;
5829

59-
if (root?.right !== null) {
60-
traverseInOrderCollector(root?.right, collect, level + 1, callbackFn);
61-
}
30+
while (indexesCopy.length > 0) {
31+
const levelSize = Math.min(
32+
indexesCopy.length,
33+
this.nodeCollector[currentLevel]?.length
34+
);
6235

63-
return collect;
64-
}
36+
const nextLevel = currentLevel + 1;
6537

66-
export function buildTree(indexes: number[][]): Node<number> {
67-
const indexesCopy: number[][] = [...indexes];
68-
const root: Node<number> = new Node<number>(__ROOT_VALUE__);
69-
let nodeCollector: Record<number, Node<number>[]> = {};
70-
71-
while (indexesCopy.length > 0) {
72-
nodeCollector = {};
73-
74-
traverseInOrderCollector(
75-
root,
76-
nodeCollector,
77-
__INITIAL_LEVEL__,
78-
callbackCollectNodes
79-
);
80-
81-
const lastLevel: number = parseInt(
82-
Object.keys(nodeCollector)
83-
.sort((a, b) => parseInt(b, __RADIX__) - parseInt(a, __RADIX__))
84-
.shift() as string,
85-
__RADIX__
86-
);
87-
88-
const levelSize = Math.min(
89-
indexesCopy.length,
90-
nodeCollector[lastLevel]?.length
91-
);
92-
for (let i = 0; i < levelSize; i++) {
93-
const currentNode: Node<number> = nodeCollector[lastLevel][i];
94-
const newElement: number[] = indexesCopy.shift() as Array<number>;
95-
96-
if ((newElement?.[0] ?? __LEAF_VALUE__) !== __LEAF_VALUE__) {
97-
currentNode.left = new Node<number>(newElement[0]);
38+
if (levelSize > 0) {
39+
this.nodeCollector[nextLevel] = [];
9840
}
99-
if ((newElement?.[1] ?? __LEAF_VALUE__) !== __LEAF_VALUE__) {
100-
currentNode.right = new Node<number>(newElement[1]);
41+
42+
for (let i = 0; i < levelSize; i++) {
43+
const currentNode = this.nodeCollector[currentLevel][i];
44+
const newElement = indexesCopy?.shift() ?? [];
45+
46+
if ((newElement?.[0] ?? __LEAF_VALUE__) !== __LEAF_VALUE__) {
47+
currentNode.left = new Node(newElement[0]);
48+
this.nodeCollector[nextLevel].push(currentNode.left);
49+
}
50+
if ((newElement?.[1] ?? __LEAF_VALUE__) !== __LEAF_VALUE__) {
51+
currentNode.right = new Node(newElement[1]);
52+
this.nodeCollector[nextLevel].push(currentNode.right);
53+
}
54+
}
55+
56+
if (this.nodeCollector[nextLevel].length > 0) {
57+
currentLevel = nextLevel;
10158
}
10259
}
60+
61+
return this;
10362
}
10463

105-
return root;
106-
}
64+
getRoot(): Node<number> {
65+
return this.root;
66+
}
10767

108-
export function flatTree(root: Node<number> | null): number[] {
109-
let nodeCollector: Record<number, Node<number>[]> = {};
68+
getCollector(): Record<number, Node<number>[]> {
69+
return this.nodeCollector;
70+
}
11071

111-
nodeCollector = traverseInOrderCollector(
112-
root,
113-
nodeCollector,
114-
__INITIAL_LEVEL__,
115-
callbackCollectFlat
116-
);
72+
flatTree(): number[] {
73+
const flatTreeCollector: Node<number>[] = [];
11774

118-
const lastLevel: number = parseInt(
119-
Object.keys(nodeCollector)
120-
.sort((a, b) => parseInt(b, __RADIX__) - parseInt(a, __RADIX__))
121-
.shift() as string,
122-
__RADIX__
123-
);
75+
function traverseInOrderFlat(node: Node<number>): void {
76+
if (node?.left !== null) {
77+
traverseInOrderFlat(node?.left);
78+
}
12479

125-
const output: number[] = [];
126-
nodeCollector[lastLevel].forEach((node: Node<number>) => {
127-
output.push(node.data);
128-
});
80+
if (node) {
81+
flatTreeCollector.push(node);
82+
}
12983

130-
return output;
84+
if (node?.right !== null) {
85+
traverseInOrderFlat(node?.right);
86+
}
87+
}
88+
89+
traverseInOrderFlat(this.root);
90+
91+
const output: number[] = [];
92+
flatTreeCollector.forEach((node) => {
93+
output.push(node.data);
94+
});
95+
96+
return output;
97+
}
13198
}
13299

133100
export function swapNodes(indexes: number[][], queries: number[]): number[][] {
134-
const tree: Node<number> = buildTree(indexes);
101+
const tree: Tree = new Tree(indexes);
102+
let nodeCollector: Record<number, Node<number>[]> = tree.getCollector();
135103
const output: number[][] = [];
136-
let nodeCollector: Record<number, Node<number>[]> = {};
137-
138-
traverseInOrderCollector(
139-
tree,
140-
nodeCollector,
141-
__INITIAL_LEVEL__,
142-
callbackCollectNodes
143-
);
144104

145105
nodeCollector = Object.fromEntries(
146106
Object.entries(nodeCollector).sort(
147107
([a], [b]) => parseInt(a, __RADIX__) - parseInt(b, __RADIX__)
148108
)
149109
);
150110

151-
let flattenedTree: number[] = flatTree(tree);
152-
153-
console.debug(`Plain tree: ${flattenedTree}`);
154-
155111
for (const query of queries) {
156112
for (const [level, nodeList] of Object.entries(nodeCollector)) {
157113
const tLevel: number = parseInt(level, __RADIX__);
@@ -164,8 +120,7 @@ export function swapNodes(indexes: number[][], queries: number[]): number[][] {
164120
}
165121
}
166122

167-
flattenedTree = flatTree(tree);
168-
output.push(flattenedTree);
123+
output.push(tree.flatTree());
169124
}
170125

171126
return output;

0 commit comments

Comments
 (0)