Skip to content

Commit f8960f5

Browse files
refactor: js | graph (#560)
Co-authored-by: Mitchell Irvin <[email protected]>
1 parent 038150e commit f8960f5

13 files changed

+1383
-482
lines changed

javascript/127-Word-Ladder.js

+45-29
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,50 @@
1-
var ladderLength = function (beginWord, endWord, wordList) {
2-
if (!wordList.includes(endWord)) return 0;
3-
let patternMap = {};
4-
wordList.push(beginWord);
5-
6-
for (let word of wordList) {
7-
for (let x = 0; x < word.length; x++) {
8-
const pattern = word.slice(0, x) + '*' + word.slice(x + 1);
9-
patternMap[pattern] = patternMap[pattern] || [];
10-
patternMap[pattern].push(word);
1+
/**
2+
* https://leetcode.com/problems/word-ladder/
3+
* Time O(ROWS * COLS) | Space O(ROWS * COLS)
4+
* @param {string} beginWord
5+
* @param {string} endWord
6+
* @param {string[]} wordList
7+
* @return {number}
8+
*/
9+
var ladderLength = function(beginWord, endWord, wordList) {
10+
const [ queue, wordSet, seen ] = [ new Queue([[ beginWord, 1 ]]), new Set(wordList), new Set([ beginWord ]) ];
11+
12+
return bfs(queue, wordSet, seen, endWord);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */
13+
};
14+
15+
const bfs = (queue, wordSet, seen, endWord) => {
16+
while (!queue.isEmpty()) {
17+
for (let i = (queue.size() - 1); 0 <= i; i--) {
18+
const [ word, depth ] = queue.dequeue();
19+
20+
const isTarget = word === endWord
21+
if (isTarget) return depth
22+
23+
transform(queue, wordSet, seen, word, depth)
1124
}
1225
}
1326

14-
let wordCount = 1,
15-
queue = [beginWord],
16-
visited = [beginWord];
17-
while (queue.length) {
18-
const levelSize = queue.length;
19-
for (let x = 0; x < levelSize; x++) {
20-
const word = queue.shift();
21-
if (word === endWord) return wordCount;
22-
for (let x = 0; x < word.length; x++) {
23-
const pattern = word.slice(0, x) + '*' + word.slice(x + 1);
24-
for (let nei of patternMap[pattern]) {
25-
if (nei in visited) continue;
26-
visited[nei] = true;
27-
queue.push(nei);
28-
}
29-
}
27+
return 0
28+
}
29+
30+
const transform = (queue, wordSet, seen, word, depth) => {
31+
for (const index in word) {
32+
for (const char of 'abcdefghijklmnopqrstuvwxyz') {
33+
const neighbor = getNeighbor(word, index, char);
34+
35+
const hasSeen = !wordSet.has(neighbor) || seen.has(neighbor);
36+
if (hasSeen) continue;
37+
38+
queue.enqueue([ neighbor, (depth + 1) ]);
39+
seen.add(neighbor);
3040
}
31-
wordCount += 1;
3241
}
33-
return 0;
34-
};
42+
}
43+
44+
const getNeighbor = (word, index, char) => {
45+
const neighbor = word.split('');
46+
47+
neighbor[index] = char;
48+
49+
return neighbor.join('');
50+
}

javascript/130-Surrounded-Regions.js

+107-52
Original file line numberDiff line numberDiff line change
@@ -1,68 +1,123 @@
1-
//////////////////////////////////////////////////////////////////////////////
2-
// Depth First Search (DFS)
3-
// Time: O(m*n)
4-
// Space: O(m*n)
5-
// You can implement either Depth First Search (DFS) or Breadth First Search
6-
// (BFS). The only noticeable impact is the performance cost of the BFS queue
7-
// is higher than the DFS call stack.
8-
//////////////////////////////////////////////////////////////////////////////
9-
101
/**
2+
* https://leetcode.com/problems/surrounded-regions/
3+
* Time O(ROWS * COLS) | Space O(ROWS * COLS)
114
* @param {character[][]} board
125
* @return {void} Do not return anything, modify board in-place instead.
136
*/
14-
function solve(board) {
15-
const rowLen = board.length;
16-
const colLen = board[0].length;
17-
const lastRow = rowLen - 1;
18-
const lastCol = colLen - 1;
19-
20-
for (let r = 0; r < rowLen; ++r) {
21-
markSeen(r, 0);
22-
markSeen(r, lastCol);
7+
var solve = function solve(board) {
8+
searchRows(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */
9+
searchCols(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */
10+
searchGrid(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */
11+
}
12+
13+
var searchRows = (board) => {
14+
const [ rows, cols ] = [ board.length, board[0].length ];
15+
16+
for (let row = 0; row < rows; row++) { /* Time O(ROWS) */
17+
dfs(board, row, rows, 0, cols); /* Space O(ROWS) */
18+
dfs(board, row, rows, (cols - 1), cols);/* Space O(ROWS) */
2319
}
24-
for (let c = 1; c < lastCol; ++c) {
25-
markSeen(0, c);
26-
markSeen(lastRow, c);
20+
}
21+
22+
var searchCols = (board) => {
23+
const [ rows, cols ] = [ board.length, board[0].length ];
24+
25+
for (let col = 1; col < (cols - 1); col++) {/* Time O(COLS) */
26+
dfs(board, 0, rows, col, cols); /* Space O(COLS) */
27+
dfs(board, (rows - 1), rows, col, cols);/* Space O(COLS) */
2728
}
29+
}
2830

29-
for (let r = 0; r < rowLen; ++r) {
30-
for (let c = 0; c < colLen; ++c) {
31-
switch (board[r][c]) {
32-
case 'O':
33-
board[r][c] = 'X';
34-
break;
35-
case 'A':
36-
board[r][c] = 'O';
37-
break;
38-
}
31+
var searchGrid = (board) => {
32+
const [ rows, cols ] = [ board.length, board[0].length ];
33+
34+
for (let row = 0; row < rows; row++) {/* Time O(ROWS) */
35+
for (let col = 0; col < cols; col++) {/* Time O(COLS) */
36+
const isO = board[row][col] === 'O';
37+
if (isO) board[row][col] = 'X';
38+
39+
const isStar = board[row][col] === '*';
40+
if (isStar) board[row][col] = 'O';
3941
}
4042
}
43+
}
4144

42-
/**
43-
* @param {number} r
44-
* @param {number} c
45-
* @return {void}
46-
*/
47-
function markSeen(r, c) {
48-
if (!inBounds(r, c) || board[r][c] !== 'O') {
49-
return;
50-
}
45+
const dfs = (board, row, rows, col, cols) => {
46+
const isBaseCase = board[row][col] !== 'O';
47+
if (isBaseCase) return;
48+
49+
board[row][col] = '*';
50+
51+
for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {
52+
dfs(board, _row, rows, _col, cols);/* Time O(HEIGHT) | Space O(HEIGHT) */
53+
}
54+
}
55+
56+
var getNeighbors = (row, rows, col, cols) => [ [0, 1], [0, -1], [1, 0], [-1, 0] ]
57+
.map(([ _row, _col ]) => [ (row + _row), (col + _col)])
58+
.filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols))
59+
60+
61+
/**
62+
* https://leetcode.com/problems/surrounded-regions/
63+
* Time O(ROWS * COLS) | Space O(ROWS * COLS)
64+
* @param {character[][]} board
65+
* @return {void} Do not return anything, modify board in-place instead.
66+
*/
67+
var solve = function solve(board, queue = new Queue([])) {
68+
searchRows(board, queue);/* Time O(ROWS + COLS) | Space O(ROWS + COLS) */
69+
searchCols(board, queue);/* Time O(ROWS + COLS) | Space O(ROWS + COLS) */
70+
bfs(board, queue); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */
71+
searchGrid(board); /* Time O(ROWS * COLS) */
72+
}
5173

52-
board[r][c] = 'A';
74+
var searchRows = (board, queue) => {
75+
const [ rows, cols ] = [ board.length, board[0].length ]
5376

54-
markSeen(r - 1, c);
55-
markSeen(r + 1, c);
56-
markSeen(r, c - 1);
57-
markSeen(r, c + 1);
77+
for (let row = 0; row < rows; row++) { /* Time O(ROWS) */
78+
queue.enqueue([ row, 0 ]); /* Space O(ROWS) */
79+
queue.enqueue([ row, (cols - 1) ]);/* Space O(ROWS) */
5880
}
81+
}
82+
83+
var searchCols = (board, queue) => {
84+
const [ rows, cols ] = [ board.length, board[0].length ]
5985

60-
/**
61-
* @param {number} r
62-
* @param {number} c
63-
* @return {boolean}
64-
*/
65-
function inBounds(r, c) {
66-
return r >= 0 && c >= 0 && r < rowLen && c < colLen;
86+
for (let col = 0; col < (cols - 1); col++) {/* Time O(COLS) */
87+
queue.enqueue([ 0, col ]); /* Space O(COLS) */
88+
queue.enqueue([ (rows - 1), col ]); /* Space O(COLS) */
6789
}
6890
}
91+
92+
var bfs = (board, queue) => {
93+
const [ rows, cols ] = [ board.length, board[0].length ];
94+
95+
while (!queue.isEmpty()) {
96+
for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(WIDTH) */
97+
const [ row, col ] = queue.dequeue();
98+
99+
const isBaseCase = board[row][col] !== 'O';
100+
if (isBaseCase) continue;
101+
102+
board[row][col] = '*';
103+
104+
for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {
105+
queue.enqueue([ _row, _col ]); /* Space O(WIDTH) */
106+
}
107+
}
108+
}
109+
}
110+
111+
var searchGrid = (board) => {
112+
const [ rows, cols ] = [ board.length, board[0].length ];
113+
114+
for (let row = 0; row < rows; row++) {/* Time O(ROWS) */
115+
for (let col = 0; col < cols; col++) {/* Time O(COLS) */
116+
const isO = board[row][col] === 'O';
117+
if (isO) board[row][col] = 'X';
118+
119+
const isStar = board[row][col] === '*';
120+
if (isStar) board[row][col] = 'O';
121+
}
122+
}
123+
}

javascript/133-Clone-Graph.js

+54-23
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,68 @@
11
/**
2-
* // Definition for a Node.
3-
* function Node(val, neighbors) {
4-
* this.val = val === undefined ? 0 : val;
5-
* this.neighbors = neighbors === undefined ? [] : neighbors;
6-
* };
2+
* https://leetcode.com/problems/clone-graph/
3+
* Time O(V + E) | Space O(N)
4+
* @param {Node} node
5+
* @return {Node}
76
*/
7+
var cloneGraph = function(node, seen = new Map()) {
8+
const isBaseCase = node === null;
9+
if (isBaseCase) return null;
10+
11+
if (seen.has(node)) return seen.get(node);
12+
13+
return dfs(node, seen); /* Time O(V + E) | Space O(N) */
14+
}
15+
16+
const dfs = (node, seen) => {
17+
const clone = new Node(node.val);
18+
19+
seen.set(node, clone); /* | Space O(N) */
20+
21+
for (const neighbor of node.neighbors) {
22+
const cloneNeighbor = cloneGraph(neighbor, seen);/* Time O(V + E) | Space O(H) */
23+
24+
clone.neighbors.push(cloneNeighbor); /* | Space O(V + E) */
25+
}
26+
27+
return clone;
28+
}
829

930
/**
31+
* https://leetcode.com/problems/clone-graph/
32+
* Time O(V + E) | Space O(N)
1033
* @param {Node} node
1134
* @return {Node}
1235
*/
13-
var cloneGraph = function (node) {
14-
let visited = {};
36+
var cloneGraph = function(node, seen = new Map()) {
37+
const isBaseCase = node === null;
38+
if (isBaseCase) return null;
1539

16-
let dfs = (node) => {
17-
if (!node) {
18-
return node;
19-
}
40+
seen.set(node, new Node(node.val)); /* | Space O(N) */
2041

21-
if (visited[node.val]) {
22-
return visited[node.val];
23-
}
42+
bfs(new Queue([ node ]), seen); /* Time O(V + E) | Space O(N) */
43+
44+
return seen.get(node);
45+
};
2446

25-
let copy = new Node(node.val);
47+
const bfs = (queue, seen) => {
48+
while (!queue.isEmpty()) { /* Time O(V + E) */
49+
for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(W) */
50+
const node = queue.dequeue();
2651

27-
visited[node.val] = copy;
52+
cloneNeighbors(node, seen, queue); /* Space O(N) */
53+
}
54+
}
55+
}
2856

29-
node.neighbors.forEach((n) => {
30-
copy.neighbors.push(dfs(n));
31-
});
57+
const cloneNeighbors = (node, seen, queue) => {
58+
for (const neighbor of node.neighbors) {
59+
if (!seen.has(neighbor)) {
60+
seen.set(neighbor, new Node(neighbor.val));/* Space O(N) */
61+
queue.enqueue(neighbor); /* Space O(W) */
62+
}
3263

33-
return copy;
34-
};
64+
const [ parentClone, neighborClone ] = [ seen.get(node), seen.get(neighbor) ];
3565

36-
return dfs(node);
37-
};
66+
parentClone.neighbors.push(neighborClone); /* Space O(V + E) */
67+
}
68+
}

0 commit comments

Comments
 (0)