题目:
Trie发音类似try或者说前缀树是一种树形数据结构,用于高效地存储和检索字符串数据集的键,这一数据结构有相当多的应用情景,例如自动补全和拼写检查
请你实现 Trie 类:
Trie()
初始化前缀树对象。void insert(String word)
向前缀树中插入字符串word
boolean search(String word)
如果字符串word
在前缀树中,返回true
(即,在检索之前已经插入);否则,返回false
boolean startsWith(String prefix)
如果之前已经插入的字符串word
的前缀之一为prefix
,返回true
;否则,返回false
方法一:字典树
Trie,又称前缀树或字典树,是一棵有根树,其每个节点包含以下字段:
指向子节点的指针数组 children,对于本题而言,数组长度为 26,即小写英文字母的数量。此时 children[0] 对应小写字母 a,children[1] 对应小写字母 b,...
布尔字段 isEnd,表示该节点是否为字符串的结尾
插入字符串
从字典树的根开始,插入字符串。对于当前字符对应的子节点,有两种情况:
- 子节点存在。沿着指针移动到子节点,继续处理下一个字符。
- 子节点不存在。创建一个新的子节点,记录在 children 数组的对应位置上,然后沿着指针移动到子节点,继续搜索下一个字符
重复以上步骤,直到处理字符串的最后一个字符,然后将当前节点标记为字符串的结尾
查找前缀
从字典树的根开始,查找前缀。对于当前字符对应的子节点,有两种情况:
- 子节点存在。沿着指针移动到子节点,继续搜索下一个字符。
- 子节点不存在。说明字典树中不包含该前缀,返回空指针。
-
重复以上步骤,直到返回空指针或搜索完前缀的最后一个字符
若搜索到了前缀的末尾,就说明字典树中存在该前缀。此外,若前缀末尾对应节点的 isEnd 为真,则说明字典树中存在该字符串。
例如:
假设字符串里面只有 a 和 b 两种字符。
insert:例如插入字符串 aab,相当于生成了一条移动方向为「左-左-右」的路径。标记最后一个节点为终止节点。再插入字符串 aabb,相当于生成了一条移动方向为「左-左-右-右」的路径。标记最后一个节点为终止节点。
search:例如查找字符串 aab,相当于查找二叉树中是否存在一条移动方向为「左-左-右」的路径,且最后一个节点是终止节点
startsWith:例如查找前缀 aa,相当于查找二叉树中是否存在一条移动方向为「左-左」的路径,无其他要求。
推广到 26 种字母,其实就是一棵 26 叉树,对于 26 叉树的每个节点,可以用哈希表,或者长为 26 的数组来存储子节点。
class Trie(object):
def __init__(self):
self.children=[None]*26 #一个长度为26的列表,代表26个小写英文字母的子节点初始时每个位置都是
self.isEnd=False #标记当前节点是否是某个单词的结尾
def searchPrefix(self,prefix):#用于查找以 prefix 开头的前缀是否存在
node=self
for ch in prefix:
ch=ord(ch)-ord("a")# 计算字符ch在 children 列表中的索引(0-25)
if not node.children[ch]:#说明前缀不存在
return None
node =node.children[ch]#继续检查下一个字符
return node
def insert(self, word):
"""
:type word: str
:rtype: None
"""
node=self
for ch in word:
ch=ord(ch)-ord("a")#将字符 ch 映射到 0 到 25 之间的索引
if not node.children[ch]:#如果 children[ch] 为空,创建新的 Trie 节点,并存
node.children[ch]=Trie()
node=node.children[ch]#移动到下一个字符的子节点
node.isEnd=True#标记 word 结束
def search(self, word):
"""
:type word: str
:rtype: bool
"""
node=self.searchPrefix(word)#查找 word 的最后一个节点
return node is not None and node.isEnd#如果 node 不为 None,并且终结点存在,则存在树中,返回true,否则返回False
def startsWith(self, prefix):
"""
:type prefix: str
:rtype: bool
"""
#检查 Trie 树中是否有以 prefix 开头的单词
return self.searchPrefix(prefix) is not None
# 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)
时间复杂度:初始化为 O(1),其余操作为 O(∣S∣),其中 ∣S∣ 是每次插入或查询的字符串的长度
空间复杂度:O(∣T∣⋅Σ),其中 ∣T∣ 为所有插入字符串的长度之和,Σ 为字符集的大小,本题 Σ=26。
源自灵茶山艾府
源自力扣官方题解