Skip to content

Commit 9eee1b9

Browse files
add post '(Leetcode) 211 - Design Add and Search Words Data Structure (Trie)'
1 parent 65c10b6 commit 9eee1b9

File tree

2 files changed

+219
-0
lines changed

2 files changed

+219
-0
lines changed

_posts/2024-06-30-leetcode-211.md

Lines changed: 219 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
---
2+
layout: post
3+
title: (Leetcode) 211 - Design Add and Search Words Data Structure (Trie)
4+
categories: [스터디-알고리즘]
5+
tags: [자바, java, 리트코드, Leetcode, 알고리즘, brute force, trie, tree]
6+
date: 2024-06-30 00:30:00 +0900
7+
toc: true
8+
---
9+
10+
기회가 되어 [달레님의 스터디](https://github.com/DaleStudy/leetcode-study)에 참여하여 시간이 될 때마다 한문제씩 풀어보고 있다.
11+
12+
[https://neetcode.io/practice](https://neetcode.io/practice)
13+
14+
---
15+
16+
[https://leetcode.com/problems/design-add-and-search-words-data-structure](https://leetcode.com/problems/design-add-and-search-words-data-structure)
17+
18+
점진적으로 개선하여 보았다.
19+
20+
## brute force
21+
22+
아슬아슬하게 통과한다.
23+
24+
```java
25+
class WordDictionary {
26+
27+
Set<String> wordSet;
28+
29+
public WordDictionary() {
30+
wordSet = new HashSet<>();
31+
}
32+
33+
public void addWord(String word) {
34+
wordSet.add(word);
35+
}
36+
37+
public boolean search(String word) {
38+
Deque<String> queue = new ArrayDeque<>();
39+
queue.push(word);
40+
41+
while (queue.getFirst().contains(".")) {
42+
String _word = queue.removeFirst();
43+
String pre = _word.substring(0, _word.indexOf("."));
44+
String post = _word.substring(_word.indexOf(".") + 1);
45+
46+
for (char c = 'a'; c <= 'z'; c++) {
47+
queue.addLast(pre + c + post);
48+
}
49+
}
50+
51+
while (!queue.isEmpty()) {
52+
String _word = queue.removeFirst();
53+
if (wordSet.contains(_word)) {
54+
return true;
55+
}
56+
}
57+
58+
return false;
59+
}
60+
}
61+
```
62+
63+
### TC, SC
64+
65+
- `.` 이 없을 때
66+
- 시간 복잡도 : `O(1)`
67+
- 공간 복잡도 : `O(1)`
68+
- `.` 이 있을 때
69+
- 시간 복잡도 : `O(26^N)`
70+
- 공간 복잡도 : `O(26^N)`
71+
- 여기서 N은 `.` 의 수
72+
73+
## trie
74+
75+
[208. Implement Trie (Prefix Tree)](https://leetcode.com/problems/implement-trie-prefix-tree/) 문제 에서 사용한 Trie 재사용.
76+
77+
```java
78+
class WordDictionary {
79+
80+
Trie trie; // Trie 구현은 생략
81+
82+
public WordDictionary() {
83+
trie = new Trie();
84+
}
85+
86+
public void addWord(String word) {
87+
trie.insert(word);
88+
}
89+
90+
public boolean search(String word) {
91+
if (word.contains(".")) {
92+
String pre = word.substring(0, word.indexOf("."));
93+
String post = word.substring(word.indexOf(".") + 1);
94+
95+
if (trie.startsWith(pre)) {
96+
for (char c = 'a'; c <= 'z'; c++) {
97+
if (search(pre + c + post)) {
98+
return true;
99+
}
100+
}
101+
}
102+
103+
return false;
104+
}
105+
106+
return trie.search(word);
107+
}
108+
109+
110+
}
111+
```
112+
113+
### TC, SC
114+
115+
입력된 문자열의 길이를 `L`, `.` 의 수를 `N` 이라고 하였을 때
116+
117+
addWord 메소드의 경우 시간 복잡도는 `O(L)`이다.
118+
search 메소드의 경우 입력된 문자열의 길이를 n 이라 하였을 때 시간 복잡도는 `O(L * 26 ^ N)`이다.
119+
120+
공간 복잡도는 Trie 구조를 만드는데 사용된 공간이다. `insert된 문자열 길이의 평균``avg(L)`이라고 하였을 때 `O(avg(L) * 26)`이다. 26은 계수이기 때문에 생략할 수 있다.
121+
122+
## trie 개선
123+
124+
이 문제에 적합하도록 search를 수정하였다.
125+
126+
```java
127+
class WordDictionary {
128+
129+
Trie trie;
130+
131+
public WordDictionary() {
132+
trie = new Trie();
133+
}
134+
135+
public void addWord(String word) {
136+
trie.insert(word);
137+
}
138+
139+
public boolean search(String word) {
140+
return trie.search(word);
141+
}
142+
143+
144+
}
145+
146+
class Trie {
147+
148+
Node root = new Node();
149+
150+
public Trie() {
151+
152+
}
153+
154+
public void insert(String word) {
155+
Node currentNode = root;
156+
for (char c : word.toCharArray()) {
157+
if (currentNode.nodes[c - 97] == null) {
158+
currentNode.nodes[c - 97] = new Node();
159+
}
160+
currentNode = currentNode.nodes[c - 97];
161+
}
162+
currentNode.val = word;
163+
}
164+
165+
public boolean search(String word) {
166+
return search(root, word, 0);
167+
}
168+
169+
public boolean search(Node node, String word, int index) {
170+
if (node == null) {
171+
return false;
172+
}
173+
174+
if (node.val != null && node.val.length() == word.length()) {
175+
return true;
176+
}
177+
178+
if (index >= word.length()) {
179+
return false;
180+
}
181+
182+
char c = word.charAt(index);
183+
184+
if (c == '.') {
185+
for (char _c = 'a'; _c <= 'z'; _c++) {
186+
if (search(node.nodes[_c - 97], word, index + 1)) {
187+
return true;
188+
}
189+
}
190+
return false;
191+
} else if (node.nodes[c - 97] == null) {
192+
return false;
193+
}
194+
195+
return search(node.nodes[c - 97], word, index + 1);
196+
}
197+
}
198+
199+
class Node {
200+
String val;
201+
Node[] nodes = new Node[26];
202+
}
203+
```
204+
205+
### TC, SC
206+
207+
입력된 문자열의 길이를 `L`, `.` 의 수를 `N` 이라고 하였을 때
208+
209+
addWord 메소드의 경우 시간 복잡도는 `O(L)`이다.
210+
search 메소드의 경우 입력된 문자열의 길이를 n 이라 하였을 때 시간 복잡도는 `O(L * 26 ^ N)`이다.
211+
개선 전과 비교해봤을 때 표기상으로는 차이가 없으나, 불필요한 과정을 제거하게되어서 시간이 매우 단축된다. (`trie.startsWith(pre)`이 사라졌고, search의 호출 횟수가 줄어듬.)
212+
213+
공간 복잡도는 Trie 구조를 만드는데 사용된 공간이다. `insert된 문자열 길이의 평균``avg(L)`이라고 하였을 때 `O(avg(L) * 26)`이다. 26은 계수이기 때문에 생략할 수 있다.
214+
215+
### submit result
216+
217+
개선된 trie 로직으로 제출결과 최상단에 위치하였다. (약 beats 95%)
218+
219+
![submit result](/assets/images/2024-06-30-leetcode-211/submit_result.png)
117 KB
Loading

0 commit comments

Comments
 (0)