Skip to content

Commit c74ebe8

Browse files
authored
Merge pull request #447 from aakhtar3/trie
refactor: js - trie
2 parents 6a91ebf + f6ad7e8 commit c74ebe8

File tree

3 files changed

+222
-105
lines changed

3 files changed

+222
-105
lines changed

javascript/208-Implement-Trie.js

Lines changed: 59 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -1,50 +1,59 @@
1-
class TrieNode {
2-
constructor() {
3-
this.children = {};
4-
this.endOfWord = false;
5-
}
6-
}
7-
8-
class Trie {
9-
constructor() {
10-
this.root = new TrieNode();
11-
}
12-
13-
insert(word) {
14-
let cur = this.root;
15-
16-
for (const c of word) {
17-
if (!(c in cur.children)) {
18-
cur.children[c] = new TrieNode();
19-
}
20-
cur = cur.children[c];
21-
}
22-
cur.endOfWord = true;
23-
}
24-
25-
search(word) {
26-
let cur = this.root;
27-
28-
for (const c of word) {
29-
if (!(c in cur.children)) {
30-
return false;
31-
}
32-
cur = cur.children[c];
33-
}
34-
35-
return cur.endOfWord;
36-
}
37-
38-
startsWith(prefix) {
39-
let cur = this.root;
40-
41-
for (const c of prefix) {
42-
if (!(c in cur.children)) {
43-
return false;
44-
}
45-
cur = cur.children[c];
46-
}
47-
48-
return true;
49-
}
50-
}
1+
/**
2+
* Your Trie object will be instantiated and called as such:
3+
* var obj = new Trie()
4+
* obj.insert(word)
5+
* var param_2 = obj.search(word)
6+
* var param_3 = obj.startsWith(prefix)
7+
*/
8+
9+
class TrieNode {
10+
constructor() {
11+
this.children = {};
12+
this.isWord = false;
13+
}
14+
}
15+
16+
class Trie {
17+
constructor () {
18+
this.root = new TrieNode();
19+
}
20+
21+
/* Time O(N) | Space O(N) */
22+
insert (word, node = this.root) {
23+
for (const char of word) {
24+
const child = node.children[char] || new TrieNode();
25+
26+
node.children[char] = child;
27+
28+
node = child;
29+
}
30+
31+
node.isWord = true;
32+
}
33+
34+
/* Time O(N) | Space O(1) */
35+
search (word, node = this.root) {
36+
for (const char of word) {
37+
const child = node.children[char] || null;
38+
39+
if (!child) return false;
40+
41+
node = child;
42+
}
43+
44+
return node.isWord;
45+
}
46+
47+
/* Time O(N) | Space O(1) */
48+
startsWith (prefix, node = this.root) {
49+
for (const char of prefix) {
50+
const child = node.children[char] || null;
51+
52+
if (!child) return false;
53+
54+
node = child;
55+
}
56+
57+
return true;
58+
}
59+
};
Lines changed: 60 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,60 @@
1-
class TrieNode {
2-
constructor() {
3-
this.children = {};
4-
this.endOfWord = false;
5-
}
6-
}
7-
8-
class WordDictionary {
9-
constructor() {
10-
this.root = new TrieNode();
11-
}
12-
13-
addWord(word) {
14-
let cur = this.root;
15-
16-
for (const c of word) {
17-
if (!(c in cur.children)) {
18-
cur.children[c] = new TrieNode();
19-
}
20-
cur = cur.children[c];
21-
}
22-
cur.endOfWord = true;
23-
}
24-
25-
search(word) {
26-
function dfs(j, root) {
27-
let cur = root;
28-
29-
for (let i = j; i < word.length; i++) {
30-
const c = word[i];
31-
32-
if (c === ".") {
33-
for (const key in cur.children) {
34-
if (Object.prototype.hasOwnProperty.call(cur.children, key)) {
35-
const child = cur.children[key];
36-
37-
if (dfs(i + 1, child)) {
38-
return true;
39-
}
40-
}
41-
}
42-
return false;
43-
} else {
44-
if (!(c in cur.children)) {
45-
return false;
46-
}
47-
cur = cur.children[c];
48-
}
49-
}
50-
51-
return cur.endOfWord;
52-
}
53-
return dfs(0, this.root);
54-
}
55-
}
1+
/**
2+
* Your WordDictionary object will be instantiated and called as such:
3+
* var obj = new WordDictionary()
4+
* obj.addWord(word)
5+
* var param_2 = obj.search(word)
6+
*/
7+
8+
class TrieNode {
9+
constructor() {
10+
this.children = {};
11+
this.isWord = false;
12+
}
13+
};
14+
15+
class WordDictionary {
16+
constructor() {
17+
this.root = new TrieNode();
18+
}
19+
20+
/* Time O(N) | Space O(N) */
21+
addWord (word, node = this.root) {
22+
for (const char of word) {
23+
const child = node.children[char] || new TrieNode();
24+
25+
node.children[char] = child;
26+
27+
node = child;
28+
}
29+
30+
node.isWord = true;
31+
}
32+
33+
/* Time O(N) | Space O(N) */
34+
search (word) {
35+
return this.dfs(word, this.root, 0);
36+
}
37+
38+
dfs (word, node, level) {
39+
if (!node) return false;
40+
41+
const isWord = level === word.length;
42+
if (isWord) return node.isWord;
43+
44+
const isWildCard = word[level] === '.';
45+
if (isWildCard) return this.hasWildCard(word, node, level);
46+
47+
return this.dfs(word, node.children[word[level]], (level + 1));
48+
}
49+
50+
hasWildCard (word, node, level) {
51+
for (const char of Object.keys(node.children)) {
52+
const child = node.children[char];
53+
54+
const hasWord = this.dfs(word, child, (level + 1));
55+
if (hasWord) return true;
56+
}
57+
58+
return false;
59+
}
60+
}

javascript/212-Word-Search-ii.js

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/**
2+
* @param {character[][]} board
3+
* @param {string[]} words
4+
* Time O((ROWS * COLS) * (4 * (3 ^ (WORDS - 1)))) | Space O(N)
5+
* @return {string[]}
6+
*/
7+
var findWords = function(board, words) {
8+
return new Trie(words).searchBoard(board);
9+
}
10+
11+
class TrieNode {
12+
constructor() {
13+
this.children = {};
14+
this.word = '';
15+
}
16+
}
17+
18+
class Trie {
19+
constructor(words) {
20+
this.root = new TrieNode();
21+
words.forEach((word) => this.insert(word));
22+
}
23+
24+
/* Time O(N) | Space O(N) */
25+
insert (word, node = this.root) {
26+
for (const char of word) {
27+
const child = node.children[char] || new TrieNode();
28+
29+
node.children[char] = child;
30+
31+
node = child;
32+
}
33+
34+
node.word = word;
35+
}
36+
37+
/* Time O((ROWS * COLS) * (4 * (3 ^ (WORDS - 1)))) | Space O(N) */
38+
searchBoard (board, node = this.root, words = []) {
39+
const [ rows, cols ] = [ board.length, board[0].length ];
40+
41+
for (let row = 0; row < rows; row++) {
42+
for (let col = 0; col < cols; col++) {
43+
this.dfs(board, row, rows, col, cols, node, words);
44+
}
45+
}
46+
47+
return words;
48+
}
49+
50+
dfs (board, row, rows, col, cols, node, words) {
51+
const char = board[row][col];
52+
const child = node.children[char] || null;
53+
54+
if (this.canSkip(char, child)) return;
55+
56+
node = child;
57+
this.checkWord(node, words);
58+
this.backTrack(board, row, rows, col, cols, node, words);
59+
}
60+
61+
62+
canSkip (char, child) {
63+
const hasSeen = char === '#';
64+
const isMissingChild = !child;
65+
66+
return hasSeen || isMissingChild;
67+
}
68+
69+
checkWord (node, words) {
70+
if (!node.word.length) return;
71+
72+
words.push(node.word);
73+
node.word = '';
74+
}
75+
76+
backTrack (board, row, rows, col, cols, node, words) {
77+
const char = board[row][col];
78+
79+
board[row][col] = '#';
80+
81+
for (const [ _row, _col ] of this.getNeighbors(row, rows, col, cols)) {
82+
this.dfs(board, _row, rows, _col, cols, node, words);
83+
}
84+
85+
board[row][col] = char;
86+
}
87+
88+
getNeighbors (row, rows, col, cols) {
89+
return [
90+
[row - 1, col],
91+
[row + 1, col],
92+
[row, col - 1],
93+
[row, col + 1]
94+
].filter(([ _row, _col ]) => !this.isOutOfBounds(_row, rows, _col, cols));
95+
}
96+
97+
isOutOfBounds(row, rows, col, cols) {
98+
const isRowOut = row < 0 || rows <= row;
99+
const isColOut = col < 0 || cols <= col;
100+
101+
return isRowOut || isColOut;
102+
}
103+
}

0 commit comments

Comments
 (0)