1/*
2 * νΈλΌμ΄ (Trie)
3 * Prefix Tree, Autocomplete, Word Search
4 *
5 * λ¬Έμμ΄ κ²μμ νΉνλ νΈλ¦¬ μλ£κ΅¬μ‘°μ
λλ€.
6 */
7
8#include <iostream>
9#include <vector>
10#include <string>
11#include <unordered_map>
12#include <memory>
13
14using namespace std;
15
16// =============================================================================
17// 1. κΈ°λ³Έ νΈλΌμ΄
18// =============================================================================
19
20class Trie {
21private:
22 struct TrieNode {
23 unordered_map<char, unique_ptr<TrieNode>> children;
24 bool isEndOfWord = false;
25 };
26
27 unique_ptr<TrieNode> root;
28
29public:
30 Trie() : root(make_unique<TrieNode>()) {}
31
32 void insert(const string& word) {
33 TrieNode* node = root.get();
34 for (char c : word) {
35 if (!node->children.count(c)) {
36 node->children[c] = make_unique<TrieNode>();
37 }
38 node = node->children[c].get();
39 }
40 node->isEndOfWord = true;
41 }
42
43 bool search(const string& word) const {
44 const TrieNode* node = root.get();
45 for (char c : word) {
46 if (!node->children.count(c)) {
47 return false;
48 }
49 node = node->children.at(c).get();
50 }
51 return node->isEndOfWord;
52 }
53
54 bool startsWith(const string& prefix) const {
55 const TrieNode* node = root.get();
56 for (char c : prefix) {
57 if (!node->children.count(c)) {
58 return false;
59 }
60 node = node->children.at(c).get();
61 }
62 return true;
63 }
64};
65
66// =============================================================================
67// 2. μλμμ± νΈλΌμ΄
68// =============================================================================
69
70class AutocompleteTrie {
71private:
72 struct TrieNode {
73 unordered_map<char, unique_ptr<TrieNode>> children;
74 bool isEndOfWord = false;
75 int frequency = 0;
76 };
77
78 unique_ptr<TrieNode> root;
79
80 void collectWords(TrieNode* node, string& current, vector<string>& result) {
81 if (node->isEndOfWord) {
82 result.push_back(current);
83 }
84 for (auto& [c, child] : node->children) {
85 current.push_back(c);
86 collectWords(child.get(), current, result);
87 current.pop_back();
88 }
89 }
90
91public:
92 AutocompleteTrie() : root(make_unique<TrieNode>()) {}
93
94 void insert(const string& word, int freq = 1) {
95 TrieNode* node = root.get();
96 for (char c : word) {
97 if (!node->children.count(c)) {
98 node->children[c] = make_unique<TrieNode>();
99 }
100 node = node->children[c].get();
101 }
102 node->isEndOfWord = true;
103 node->frequency += freq;
104 }
105
106 vector<string> autocomplete(const string& prefix) {
107 vector<string> result;
108 TrieNode* node = root.get();
109
110 for (char c : prefix) {
111 if (!node->children.count(c)) {
112 return result;
113 }
114 node = node->children[c].get();
115 }
116
117 string current = prefix;
118 collectWords(node, current, result);
119 return result;
120 }
121};
122
123// =============================================================================
124// 3. μμΌλμΉ΄λ κ²μ νΈλΌμ΄
125// =============================================================================
126
127class WildcardTrie {
128private:
129 struct TrieNode {
130 TrieNode* children[26] = {nullptr};
131 bool isEndOfWord = false;
132 ~TrieNode() {
133 for (auto& child : children) delete child;
134 }
135 };
136
137 TrieNode* root;
138
139 bool searchHelper(TrieNode* node, const string& word, int idx) {
140 if (!node) return false;
141 if (idx == (int)word.size()) return node->isEndOfWord;
142
143 char c = word[idx];
144 if (c == '.') {
145 // μμΌλμΉ΄λ: λͺ¨λ μμ νμ
146 for (int i = 0; i < 26; i++) {
147 if (searchHelper(node->children[i], word, idx + 1)) {
148 return true;
149 }
150 }
151 return false;
152 } else {
153 return searchHelper(node->children[c - 'a'], word, idx + 1);
154 }
155 }
156
157public:
158 WildcardTrie() : root(new TrieNode()) {}
159 ~WildcardTrie() { delete root; }
160
161 void addWord(const string& word) {
162 TrieNode* node = root;
163 for (char c : word) {
164 int idx = c - 'a';
165 if (!node->children[idx]) {
166 node->children[idx] = new TrieNode();
167 }
168 node = node->children[idx];
169 }
170 node->isEndOfWord = true;
171 }
172
173 bool search(const string& word) {
174 return searchHelper(root, word, 0);
175 }
176};
177
178// =============================================================================
179// 4. λ¨μ΄ μ¬μ (Word Break)
180// =============================================================================
181
182class WordDictionary {
183private:
184 struct TrieNode {
185 unordered_map<char, TrieNode*> children;
186 bool isEnd = false;
187 };
188
189 TrieNode* root;
190
191public:
192 WordDictionary() : root(new TrieNode()) {}
193
194 void addWord(const string& word) {
195 TrieNode* node = root;
196 for (char c : word) {
197 if (!node->children.count(c)) {
198 node->children[c] = new TrieNode();
199 }
200 node = node->children[c];
201 }
202 node->isEnd = true;
203 }
204
205 bool wordBreak(const string& s) {
206 int n = s.size();
207 vector<bool> dp(n + 1, false);
208 dp[0] = true;
209
210 for (int i = 1; i <= n; i++) {
211 TrieNode* node = root;
212 for (int j = i - 1; j >= 0 && node; j--) {
213 node = node->children.count(s[j]) ? node->children[s[j]] : nullptr;
214 if (node && node->isEnd && dp[j]) {
215 dp[i] = true;
216 break;
217 }
218 }
219 }
220
221 return dp[n];
222 }
223};
224
225// =============================================================================
226// 5. XOR νΈλΌμ΄ (μ΅λ XOR μ°ΎκΈ°)
227// =============================================================================
228
229class XORTrie {
230private:
231 struct TrieNode {
232 TrieNode* children[2] = {nullptr, nullptr};
233 };
234
235 TrieNode* root;
236 static const int MAX_BITS = 31;
237
238public:
239 XORTrie() : root(new TrieNode()) {}
240
241 void insert(int num) {
242 TrieNode* node = root;
243 for (int i = MAX_BITS; i >= 0; i--) {
244 int bit = (num >> i) & 1;
245 if (!node->children[bit]) {
246 node->children[bit] = new TrieNode();
247 }
248 node = node->children[bit];
249 }
250 }
251
252 int getMaxXOR(int num) {
253 TrieNode* node = root;
254 int maxXor = 0;
255 for (int i = MAX_BITS; i >= 0; i--) {
256 int bit = (num >> i) & 1;
257 int oppositeBit = 1 - bit;
258
259 if (node->children[oppositeBit]) {
260 maxXor |= (1 << i);
261 node = node->children[oppositeBit];
262 } else if (node->children[bit]) {
263 node = node->children[bit];
264 } else {
265 break;
266 }
267 }
268 return maxXor;
269 }
270};
271
272int findMaximumXOR(const vector<int>& nums) {
273 XORTrie trie;
274 int maxXor = 0;
275
276 for (int num : nums) {
277 trie.insert(num);
278 maxXor = max(maxXor, trie.getMaxXOR(num));
279 }
280
281 return maxXor;
282}
283
284// =============================================================================
285// ν
μ€νΈ
286// =============================================================================
287
288int main() {
289 cout << "============================================================" << endl;
290 cout << "νΈλΌμ΄ μμ " << endl;
291 cout << "============================================================" << endl;
292
293 // 1. κΈ°λ³Έ νΈλΌμ΄
294 cout << "\n[1] κΈ°λ³Έ νΈλΌμ΄" << endl;
295 Trie trie;
296 trie.insert("apple");
297 trie.insert("app");
298 trie.insert("application");
299 cout << " μ½μ
: apple, app, application" << endl;
300 cout << " search(\"apple\"): " << (trie.search("apple") ? "μμ" : "μμ") << endl;
301 cout << " search(\"app\"): " << (trie.search("app") ? "μμ" : "μμ") << endl;
302 cout << " search(\"appl\"): " << (trie.search("appl") ? "μμ" : "μμ") << endl;
303 cout << " startsWith(\"app\"): " << (trie.startsWith("app") ? "μ" : "μλμ€") << endl;
304
305 // 2. μλμμ±
306 cout << "\n[2] μλμμ±" << endl;
307 AutocompleteTrie autoTrie;
308 autoTrie.insert("hello");
309 autoTrie.insert("help");
310 autoTrie.insert("helicopter");
311 autoTrie.insert("hero");
312 autoTrie.insert("world");
313
314 cout << " λ¨μ΄: hello, help, helicopter, hero, world" << endl;
315 auto suggestions = autoTrie.autocomplete("hel");
316 cout << " \"hel\" μλμμ±: ";
317 for (const auto& s : suggestions) cout << s << " ";
318 cout << endl;
319
320 // 3. μμΌλμΉ΄λ κ²μ
321 cout << "\n[3] μμΌλμΉ΄λ κ²μ" << endl;
322 WildcardTrie wcTrie;
323 wcTrie.addWord("bad");
324 wcTrie.addWord("dad");
325 wcTrie.addWord("mad");
326 cout << " λ¨μ΄: bad, dad, mad" << endl;
327 cout << " search(\".ad\"): " << (wcTrie.search(".ad") ? "μμ" : "μμ") << endl;
328 cout << " search(\"b..\"): " << (wcTrie.search("b..") ? "μμ" : "μμ") << endl;
329
330 // 4. λ¨μ΄ λΆλ¦¬
331 cout << "\n[4] λ¨μ΄ λΆλ¦¬ (Word Break)" << endl;
332 WordDictionary dict;
333 dict.addWord("leet");
334 dict.addWord("code");
335 cout << " μ¬μ : [leet, code]" << endl;
336 cout << " \"leetcode\" λΆλ¦¬ κ°λ₯: " << (dict.wordBreak("leetcode") ? "μ" : "μλμ€") << endl;
337
338 // 5. μ΅λ XOR
339 cout << "\n[5] μ΅λ XOR" << endl;
340 vector<int> nums = {3, 10, 5, 25, 2, 8};
341 cout << " λ°°μ΄: [3, 10, 5, 25, 2, 8]" << endl;
342 cout << " μ΅λ XOR: " << findMaximumXOR(nums) << endl;
343
344 // 6. 볡μ‘λ μμ½
345 cout << "\n[6] 볡μ‘λ μμ½" << endl;
346 cout << " | μ°μ° | μκ°λ³΅μ‘λ | L: λ¬Έμμ΄ κΈΈμ΄ |" << endl;
347 cout << " |-------------|------------|-----------------|" << endl;
348 cout << " | μ½μ
| O(L) | |" << endl;
349 cout << " | κ²μ | O(L) | |" << endl;
350 cout << " | μ λμ¬ κ²μ | O(L) | |" << endl;
351 cout << " | μλμμ± | O(L + K) | K: κ²°κ³Ό μ |" << endl;
352 cout << " | 곡κ°λ³΅μ‘λ | O(ALPHABET Γ L Γ N) | |" << endl;
353
354 cout << "\n============================================================" << endl;
355
356 return 0;
357}