Skip to content

Commit f83b557

Browse files
committed
feat: Design Add And Search Words Data Structure 문제 풀이
1 parent 61954dc commit f83b557

File tree

1 file changed

+99
-0
lines changed
  • design-add-and-search-words-data-structure

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
class TrieNode:
2+
def __init__(self):
3+
self.children = {}
4+
self.is_end_word = False
5+
6+
7+
class WordDictionary:
8+
9+
def __init__(self):
10+
self.root = TrieNode()
11+
12+
def addWord(self, word: str) -> None:
13+
node = self.root
14+
for char in word:
15+
if char not in node.children:
16+
node.children[char] = TrieNode()
17+
node = node.children[char]
18+
node.is_end_word = True
19+
20+
def search(self, word: str) -> bool:
21+
return self._dfs(self.root, word, 0)
22+
23+
def _dfs(self, node: TrieNode, word: str, index: int) -> bool:
24+
# 단어 끝에 도달하면 is_end_word 확인
25+
if index == len(word):
26+
return node.is_end_word
27+
28+
char = word[index]
29+
30+
if char == '.':
31+
# '.'는 모든 자식 노드 탐색
32+
for child in node.children.values():
33+
if self._dfs(child, word, index + 1):
34+
return True
35+
return False
36+
else:
37+
# 일반 문자는 해당 자식으로 이동
38+
if char not in node.children:
39+
return False
40+
return self._dfs(node.children[char], word, index + 1)
41+
42+
43+
"""
44+
================================================================================
45+
풀이 과정
46+
================================================================================
47+
48+
[1차 시도] 길이별 그룹화 + 브루트포스 매칭
49+
────────────────────────────────────────────────────────────────────────────────
50+
1. 아이디어: 같은 길이 단어끼리 묶고, 하나씩 패턴 비교
51+
words = { 3: ["bad", "dad", "mad"] }
52+
search(".ad") → 모든 길이 3 단어와 비교
53+
54+
2. 문제점: Time Limit Exceeded!
55+
- 같은 길이 단어가 많으면 O(N × L) 반복
56+
- LeetCode 테스트케이스에서 시간 초과
57+
58+
3. 더 효율적인 방법 필요 → Trie로 접근
59+
60+
────────────────────────────────────────────────────────────────────────────────
61+
[2차 시도] Trie (트라이) 자료구조
62+
────────────────────────────────────────────────────────────────────────────────
63+
4. Trie 구조 (bad, dad, mad 저장 후):
64+
65+
root
66+
├── 'b' → 'a' → 'd' (is_end_word=True)
67+
├── 'd' → 'a' → 'd' (is_end_word=True)
68+
└── 'm' → 'a' → 'd' (is_end_word=True)
69+
70+
5. 동작 예시:
71+
72+
search("bad"):
73+
root → 'b' → 'a' → 'd' → is_end_word=True → True
74+
75+
search(".ad"):
76+
root → '.' (모든 자식 탐색)
77+
→ 'b' → 'a' → 'd' → True (첫 번째에서 찾음!)
78+
79+
search("b.."):
80+
root → 'b' → '.' (모든 자식)
81+
→ 'a' → '.' (모든 자식)
82+
→ 'd' → True
83+
84+
6. 왜 Trie가 더 빠른가?
85+
- 정확한 문자: O(1)로 해당 자식만 탐색
86+
- '.': 해당 위치에서만 분기, 이후는 다시 좁혀짐
87+
- 브루트포스: 모든 단어를 처음부터 끝까지 비교
88+
89+
7. 시간복잡도:
90+
- addWord: O(L) - L은 단어 길이
91+
- search: O(L) ~ O(26^m) - m은 '.' 개수 (보통 적음)
92+
93+
8. 공간복잡도: O(N × L) - 모든 단어의 문자 저장
94+
95+
9. 구현 포인트:
96+
- TrieNode 클래스 분리 → 가독성 향상
97+
- _dfs 재귀로 '.' 처리 → 모든 자식 탐색
98+
- is_end_word로 단어 끝 표시 → 접두사와 구분
99+
"""

0 commit comments

Comments
 (0)