时间复杂度:O(n)
解题思路
令每个结点都有一个长度为26的数组,专门用来保存下一个字母的结点。并且每个结点都有一个变量记录该结点是否为一个单词的最后一个字母。
对于插入操作的实现,需要遍历单词的所有字母,然后根据顺序给每个字母添加结点,最后一个字母结点的isWord为true,表示是一个单词的结尾了。
对于查找前缀树中是否有一个指定的单词,那就需要遍历该单词的所有字母然后按照顺序遍历前缀树,如果没有找到其中一个字母就返回false说明没有该前缀。如果能顺利遍历前缀树,还要判断最后一个结点的isWord变量是否为true,如果不是说明当前节点是前缀的一部分,而前缀树中并没有与该前缀相同的单词,所以还是要返回一个false。只有当这两个条件都满足才能返回true。
对于查找前缀树中是否有一个指定的前缀,方法与查找单词基本相同,只是无需判断isWord变量,因为我们要找的是前缀,只要能根据前缀的所有字母顺利遍历前缀树即可。
AC笔记
type Trie struct {
children [26]*Trie//a_z26个字母
isWord bool//截止到该结点是否是一个单词
}
func Constructor() Trie {
return Trie{}
}
func (this *Trie) Insert(word string) {
p:=this
//遍历单词的所有字母
for _,ch:=range word{
ch-='a'
if p.children[ch]==nil{
p.children[ch]=&Trie{}//该字母不在孩子结点中就创建一个结点
}
p=p.children[ch]
}
p.isWord=true//最后一个字母结点为单词结尾
}
func (this *Trie) Search(word string) bool {
node:=this.searchPrefix(word)
return node!=nil&&node.isWord//结点不为空说明有该前缀,isWord保证这是单词的最后一个字母
}
func (this *Trie) StartsWith(prefix string) bool {
return this.searchPrefix(prefix)!=nil//不为空指针就说明有该前缀
}
//查找前缀是否在前缀树中,如果在则返回最后一个字母结点指针,否则返回nil
func (this *Trie) searchPrefix(prefix string)*Trie{
p:=this
for _,ch:=range prefix{
ch-='a'
if p.children[ch]==nil{
return nil
}
p=p.children[ch]
}
return p
}
/**
* Your Trie object will be instantiated and called as such:
* obj := Constructor();
* obj.Insert(word);
* param_2 := obj.Search(word);
* param_3 := obj.StartsWith(prefix);
*/
感悟
前缀树中最关键的是长度为26的孩子数组,isWord变量记录是否是一个单词。