class TrieNode:
def __init__(self):
self.word = False
self.children = collections.defaultdict(TrieNode)
class Trie:
def __init__(self):
"""
Initialize your data structure here.
"""
self.root = TrieNode()
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
node = self.root
for char in word:
node = node.children[char]
node.word = True
# 단어 존재 여부 판별
def search(self, word: str) -> bool:
"""
Returns if the word is in the trie.
"""
node = self.root
for char in word:
if char not in node.children:
return False
node = node.children[char]
return node.word
#문자열로 시작 단어 존재 여부 판별
def startsWith(self, prefix: str) -> bool:
"""
Returns if there is any word in the trie that starts with the given prefix.
"""
node = self.root
for char in prefix:
if char not in node.children:
return False
node = node.children[char]
return True
# Your Trie object will be instantiated and called as such:
# obj = Trie()
# obj.insert(word)
# param_2 = obj.search(word)
# param_3 = obj.startsWith(prefix)
트라이를 직접 구현해보는 문제다. 여기서는 딕셔너리를 이용해 가급적 간결한 형태로 풀이해본다.
먼저 트라이를 저장할 노드는 별도 클래스로 선언한다.
트라이 연산을 구현할 별도 클래스를 선언하고 삽입 메소드를 구현한다.
def insert(self, word: str) -> None:
"""
Inserts a word into the trie.
"""
node = self.root
for char in word:
if char not in node.children:
node.children[char] = TrieNode()
node = node.children[char]
node.word = True
t = Trie()
t.insert('apple')
<apple이 추가된 트라이>
이 그림에서 트라이는 다음 문자를 키로하는 자식 노드 형태로 점점 깊어지면서, 각각의 노드는 word
값을 갖는다.
이 값은 단어가 모두 완성되었을 때만 True
가 된다.
즉 apple의 경우 단어가 모두 완성되는 e에 이르러서야 True
로 셋팅된다.
t.insert('appear')
t.insert('appeal')
<apple 트라이에 appear, appeal 단어가 추가된 트라이>
이 그림에서 트라이는, 같은 문자가 같은 자식을 타고 내려가다가, 달라지는 문자부터 서로 다른 노드로 분기된다.
마지막에는 appeal과 appear가 완성되는 l과 r노드가 각각 True
로 셋팅된다.
여기까지가 삽입의 기본 원리다.
값이 존재하는지 확인하려면 어떻게 해야할까
search()
는 단어가 존재하는지 여부를 판별하는 것이고
startsWith()
는 해당 문자열로 시작하는 단어가 존재하는지 여부를 판별한다.
둘 다 동일하게 문자 단위로 계속 깊이 탐색을 하고 search()
의 경우에만 마지막에 word
가 True
인지 확인하면 될 것이다.
search()
를 구현해보자.
문자열에서 문자를 하나씩 for 반복문으로 순회하면서 자식 노드로 계속 타고 내려간다. 그리고 마지막에 node.word
여부를 리턴한다.
단어가 완선된 트라이라면 True
로 되어 있을 것이고, 이때 True
가 결과로 리턴된다.
startsWith()
를 구현해보자.
search()
와 거의 동일하나, 차이점은 node.word
를 확인하지 않고, 자식 노드가 존재하는지 여부만 판별한다는 점이다.
자식 노드가 존재한다면 for 반복문을 끝까지 빠져나올 것이고, True
를 리턴한다.
코드를 줄여보자.
self.children
을 defaultdict()
로 선언한다면 insert()
삽입 메소드에서 매번 if로 체크하는 구문은 없앨 수 있을 것 같다.