Trie:字符串匹配剪枝
Autocomplete & Autocorrection
Bob和Alice在设计一个英文输入法产品,能把用户的输入和英文词典中的单词匹配。
如何找到所有可能匹配的单词?
Bob:“我们不如把用户的输入和所有词典中的单词比较一下,然后找出匹配就好了。“
Alice:“这样可以!不过感觉我在翻词典的时候会这样:如果找tea这个单词,先翻到t开头的一页,然后再翻到te开头那一页,里面有tea啊,ted啊之类的,这样比把每一个单词从词典里拿出来比较快多了!“
像这样把所有单词放在一个词典里的数据结构就是字典树,在字典树里查找一个单词模拟了上述翻词典的过程。
参考代码(Trie的具体实现见后面):
def getWords(swipes, trie):
def helper(i, root, word):
if i==len(swipes): return
if root.isWord:
res.append(word)
return
ch = swipes[i]
if ch in root.children:
helper(i+1, root.children[ch], word+ch)
helper(i+1, root, word)
res = []
helper(0, trie.root, "")
return res
words = ["apple", "boba", "tea", "car"]
swipe = "bnhjkiocikjhanbvcxszarm"
getWords(swipe, Trie(words)) == {'boba', 'car'}
# 回溯写法
def getWords(swipes, trie):
def helper(i, path, word):
if i==len(swipes): return
if path[-1].isWord:
res.append(word)
return
ch = swipes[i]
if ch in path[-1].children:
path.append(path[-1].children[ch])
helper(i+1, path, word+ch)
path.pop()
return
res = []
helper(0, [trie.root], "")
return res前缀树
字典树(Trie)又叫前缀树(Prefix Tree),本质是Dict:char->Dict。
当然我们可以把Dict抽象成一个TrieNode以便我们在Node当中存储其他数据,比如说isWord来表示是不是叶节点:如果是字典的话就表示我是不是形成一个单词。或者如下图所示保存单词的频率,例如tea出现了3次。

Dict简单实现
下面是Trie用字典的实现。如果不需要在node上存更多比如频率的信息,可以偷懒实现:直接用特殊字符比如#:True来表示isWord=True。
主要功能:
insert(word):O(L)插入一个word,L为单词的长度。 实现:遍历Dict中含有word字符的节点TrieNode,没有则插入新的节点。标记最后的节点为终止字符isWord=True。search(word):O(L)查找一个word,L为单词的长度。 实现:遍历Dict中含有word字符的节点TrieNode,没有则返回False,最后验证是否停留在终止字符返回isWord。startsWith(prefix):O(L)查找一个prefix,L为前缀的长度。 实现:遍历Dict中含有word字符的节点TrieNode,没有则返回False,最后返回True。
例题:最大异或值
把二进制当成字符串,从右向左每一位插入Trie。建完Trie以后再找最大异或值,从右向左找最多 的儿子,1)找到就向儿子走,2)没找到就向bit走(因为有可能之后还可能找到的儿子)。
Last updated
Was this helpful?