【leetcode】实现Tire(前缀树)
1、题目描述
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补全和拼写检查。
请你实现 Trie 类:
Trie()
初始化前缀树对象。void insert(String word)
向前缀树中插入字符串word
。boolean search(String word)
如果字符串word
在前缀树中,返回true
(即,在检索之前已经插入);否则,返回false
。boolean startsWith(String prefix)
如果之前已经插入的字符串word
的前缀之一为prefix
,返回true
;否则,返回false
。
2、初始思路
2.1 思路
在 Trie 树中,每个节点代表一个字符,并且可以有多个子节点,每个子节点代表下一个字符。由于本题只处理 小写英文字母(a-z),所以 Trie 树的每个节点最多有 26 个子节点,形成26 叉树。
(1)首先定义树的节点:
class Node:
_slots_ = 'son','end'
def __init__(self):
self.end = False
self.son = {}
其中,_slot_的作用有两个,分别为:1、优化内存使用;2、限制动态属性添加。
(1)在处理insert时:
从 root 节点开始,逐个字符检查: 若 c 不在 cur.son 中,则新建一个 Node() 并添加到 cur.son[c];继续移动到 cur.son[c] 进行下一步处理;最后 cur.end = True,表示该路径上的最后一个节点是一个完整单词的结尾。
def insert(self, word: str) -> None:
cur = self.root
for c in word:
if c not in cur.son:
cur.son[c] = Node()
cur = cur.son[c]
cur.end = True
插入 "apple"
过程如下:
root
├── 'a' -> Node
│ ├── 'p' -> Node
│ │ ├── 'p' -> Node
│ │ │ ├── 'l' -> Node
│ │ │ │ ├── 'e' -> Node(end=True)
而当插入“apple"后,再次插入”app“时,直接将最后一个字母"p”的end设置为True即可。插入后可显示为:
root
├── 'a' -> Node
│ ├── 'p' -> Node
│ │ ├── 'p' -> Node(end=True)
│ │ │ ├── 'l' -> Node
│ │ │ │ ├── 'e' -> Node(end=True)
(2)在定义search和startwith时,很明显可以使用同一个find函数,当查找到end=True时,满足search,此外,只要能找到字母,就满足startwith的要求。
def find(self, word: str) -> bool:
cur = self.root
for c in word:
if c not in cur.son:
return 0
cur = cur.son[c]
return 2 if cur.end else 1
def search(self, word: str) -> bool:
return self.find(word) == 2
def startsWith(self, prefix: str) -> bool:
return self.find(prefix) != 0
2.2 完整代码
class Node:
_slots_ = 'end', 'son'
def __init__(self):
self.son = {}
self.end = False
class Trie:
def __init__(self):
self.root = Node()
def insert(self, word: str) -> None:
cur = self.root
for c in word:
if c not in cur.son:
cur.son[c] = Node()
cur = cur.son[c]
cur.end = True
def find(self, word: str) -> bool:
cur = self.root
for c in word:
if c not in cur.son:
return 0
cur = cur.son[c]
return 2 if cur.end else 1
def search(self, word: str) -> bool:
return self.find(word) == 2
def startsWith(self, prefix: str) -> bool:
return self.find(prefix) != 0
# 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)