Skip to content

Commit 1a8ba73

Browse files
committed
Implement Trie (Prefix Tree)
1 parent 5a677bd commit 1a8ba73

File tree

1 file changed

+115
-0
lines changed

1 file changed

+115
-0
lines changed
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
/**
2+
* @problem
3+
* Trie๋ฅผ ๊ตฌํ˜„ํ•ฉ๋‹ˆ๋‹ค.
4+
* - ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์„ ์ตœ์ ํ™”ํ•˜๋ฉด์„œ ์ •ํ™•ํ•œ ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ๋ฅผ ๋ณด์žฅํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
5+
*
6+
* @example
7+
* const trie = new Trie();
8+
* trie.insert("apple"); // undefined
9+
* trie.search("apple"); // true
10+
* trie.search("app"); // false
11+
* trie.startsWith("app"); // true
12+
* trie.insert("app"); // undefined
13+
* trie.search("app"); // true
14+
*
15+
* @description
16+
* - ์‹œ๊ฐ„๋ณต์žก๋„:
17+
* ใ„ด insert: O(m) (m์€ ๋‹จ์–ด ๊ธธ์ด)
18+
* ใ„ด search: O(m) (m์€ ๋‹จ์–ด ๊ธธ์ด)
19+
* ใ„ด startsWith: O(m) (m์€ ์ ‘๋‘์‚ฌ ๊ธธ์ด)
20+
* - ๊ณต๊ฐ„๋ณต์žก๋„: O(ALPHABET_SIZE * m * n)
21+
* ใ„ด ALPHABET_SIZE: ๋ฌธ์ž์—ด์˜ ์•ŒํŒŒ๋ฒณ ์ˆ˜ (์˜๋ฌธ์˜ ๊ฒฝ์šฐ 26)
22+
* ใ„ด m: ๋‹จ์–ด์˜ ํ‰๊ท  ๊ธธ์ด
23+
*/
24+
class TrieNode {
25+
constructor() {
26+
// ๊ฐ ๋ฌธ์ž๋ฅผ ํ‚ค๋กœ ํ•˜๊ณ  ์ž์‹ ๋…ธ๋“œ๋ฅผ ๊ฐ’์œผ๋กœ ํ•˜๋Š” ๊ฐ์ฒด
27+
this.children = {};
28+
// ํ˜„์žฌ ๋…ธ๋“œ๊ฐ€ ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์ธ์ง€ ํ‘œ์‹œํ•˜๋Š” ํ”Œ๋ž˜๊ทธ
29+
this.isEndOfWord = false;
30+
}
31+
}
32+
33+
class Trie {
34+
constructor() {
35+
// ๋นˆ ๋ฌธ์ž์—ด์„ ๋‚˜ํƒ€๋‚ด๋Š” ๋ฃจํŠธ ๋…ธ๋“œ ์ƒ์„ฑ
36+
this.root = new TrieNode();
37+
}
38+
39+
/**
40+
* ๋‹จ์–ด๋ฅผ Trie์— ์‚ฝ์ž…ํ•˜๋Š” ๋ฉ”์„œ๋“œ
41+
* @param {string} word - ์‚ฝ์ž…ํ•  ๋‹จ์–ด
42+
*/
43+
insert(word) {
44+
// ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘
45+
let node = this.root;
46+
47+
// ๋‹จ์–ด์˜ ๊ฐ ๋ฌธ์ž๋ฅผ ์ˆœํšŒ
48+
for (let i = 0; i < word.length; i++) {
49+
const char = word[i];
50+
// ํ˜„์žฌ ๋ฌธ์ž์— ๋Œ€ํ•œ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด ์ƒˆ๋กœ ์ƒ์„ฑ
51+
if (!(char in node.children)) {
52+
node.children[char] = new TrieNode();
53+
}
54+
// ๋‹ค์Œ ๋ฌธ์ž๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ๋…ธ๋“œ๋กœ ์ด๋™
55+
node = node.children[char];
56+
}
57+
// ๋‹จ์–ด์˜ ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์ž„์„ ํ‘œ์‹œ
58+
node.isEndOfWord = true;
59+
}
60+
61+
62+
/**
63+
* ์ •ํ™•ํ•œ ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ
64+
* @param {string} word - ๊ฒ€์ƒ‰ํ•  ๋‹จ์–ด
65+
* @returns {boolean} - ๋‹จ์–ด ์กด์žฌ ์—ฌ๋ถ€
66+
*/
67+
search(word) {
68+
// ๋‹จ์–ด๋ฅผ ์ฐพ์•„ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜
69+
const node = this._traverse(word);
70+
// ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜๊ณ  ํ•ด๋‹น ๋…ธ๋“œ๊ฐ€ ๋‹จ์–ด์˜ ๋์ธ ๊ฒฝ์šฐ์—๋งŒ true ๋ฐ˜ํ™˜
71+
return node !== null && node.isEndOfWord;
72+
}
73+
74+
/**
75+
* ์ฃผ์–ด์ง„ ์ ‘๋‘์‚ฌ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹จ์–ด๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€ ๊ฒ€์ƒ‰ํ•˜๋Š” ๋ฉ”์„œ๋“œ
76+
* @param {string} prefix - ๊ฒ€์ƒ‰ํ•  ์ ‘๋‘์‚ฌ
77+
* @returns {boolean} - ์ ‘๋‘์‚ฌ๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋‹จ์–ด ์กด์žฌ ์—ฌ๋ถ€
78+
*/
79+
startsWith(prefix) {
80+
// ์ ‘๋‘์‚ฌ์— ํ•ด๋‹นํ•˜๋Š” ๋…ธ๋“œ๊ฐ€ ์กด์žฌํ•˜๋Š”์ง€๋งŒ ํ™•์ธ
81+
return this._traverse(prefix) !== null;
82+
}
83+
84+
/**
85+
* ๋ฌธ์ž์—ด์„ ๋”ฐ๋ผ๊ฐ€๋ฉฐ ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ๋‚ด๋ถ€ ํ—ฌํผ ๋ฉ”์„œ๋“œ
86+
* @param {string} str - ํƒ์ƒ‰ํ•  ๋ฌธ์ž์—ด
87+
* @returns {TrieNode|null} - ๋งˆ์ง€๋ง‰ ๋ฌธ์ž์— ํ•ด๋‹นํ•˜๋Š” ๋…ธ๋“œ ๋˜๋Š” null
88+
* @private
89+
*/
90+
_traverse(str) {
91+
// ๋ฃจํŠธ ๋…ธ๋“œ๋ถ€ํ„ฐ ์‹œ์ž‘
92+
let node = this.root;
93+
94+
// ๋ฌธ์ž์—ด์˜ ๊ฐ ๋ฌธ์ž๋ฅผ ์ˆœํšŒ
95+
for (let i = 0; i < str.length; i++) {
96+
const char = str[i];
97+
// ํ˜„์žฌ ๋ฌธ์ž์— ๋Œ€ํ•œ ๋…ธ๋“œ๊ฐ€ ์—†์œผ๋ฉด null ๋ฐ˜ํ™˜
98+
if (!(char in node.children)) {
99+
return null;
100+
}
101+
// ๋‹ค์Œ ๋ฌธ์ž๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ž์‹ ๋…ธ๋“œ๋กœ ์ด๋™
102+
node = node.children[char];
103+
}
104+
// ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ ๋ฐ˜ํ™˜
105+
return node;
106+
}
107+
}
108+
109+
const trie = new Trie();
110+
console.log(trie.insert("apple")); // undefined
111+
console.log(trie.search("apple")); // true
112+
console.log(trie.search("app")); // false
113+
console.log(trie.startsWith("app")); // true
114+
console.log(trie.insert("app")); // undefined
115+
console.log(trie.search("app")); // true

0 commit comments

Comments
ย (0)