实现 Trie (前缀树)
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", "insert", "search", "search", "startsWith", "insert", "search"]
[[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
输出
[null, null, true, false, true, null, true]
解释
Trie trie = new Trie();
trie.insert("apple");
trie.search("apple"); // 返回 True
trie.search("app"); // 返回 False
trie.startsWith("app"); // 返回 True
trie.insert("app");
trie.search("app"); // 返回 True
题解:
本身没有特别的算法上的难度,但是还是建议当做模板背诵下来
type Trie struct {
children map[byte]*Trie
isEnd bool
}
func Constructor() Trie {
return Trie{children: make(map[byte]*Trie)}
}
func (this *Trie) Insert(word string) {
node := this
for i := 0; i < len(word); i++ {
ch := word[i]
if _, exists := node.children[ch]; !exists {
node.children[ch] = &Trie{children: make(map[byte]*Trie)}
}
node = node.children[ch]
}
node.isEnd = true
}
func (this *Trie) Search(word string) bool {
node := this
for i := 0; i < len(word); i++ {
ch := word[i]
if _, exists := node.children[ch]; !exists {
return false
}
node = node.children[ch]
}
return node.isEnd
}
func (this *Trie) StartsWith(prefix string) bool {
node := this
for i := 0; i < len(prefix); i++ {
ch := prefix[i]
if _, exists := node.children[ch]; !exists {
return false
}
node = node.children[ch]
}
return true
}
/**
* 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);
*/
当然,你也可以使用数组而不是 map
type Trie struct {
children [26]*Trie
isEnd bool
}
func Constructor() Trie {
return Trie{}
}
func (this *Trie) Insert(word string) {
node := this
for i := 0; i < len(word); i++ {
ch := word[i] - 'a'
if node.children[ch] == nil {
node.children[ch] = &Trie{}
}
node = node.children[ch]
}
node.isEnd = true
}
func (this *Trie) Search(word string) bool {
node := this
for i := 0; i < len(word); i++ {
ch := word[i] - 'a'
if node.children[ch] == nil {
return false
}
node = node.children[ch]
}
return node.isEnd
}
func (this *Trie) StartsWith(prefix string) bool {
node := this
for i := 0; i < len(prefix); i++ {
ch := prefix[i] - 'a'
if node.children[ch] == nil {
return false
}
node = node.children[ch]
}
return true
}
/**
* 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);
*/
另外,附一下题解的代码,虽然差别不是很大
type Trie struct {
children [26]*Trie
isEnd bool
}
func Constructor() Trie {
return Trie{}
}
func (t *Trie) Insert(word string) {
node := t
for _, ch := range word {
ch -= 'a'
if node.children[ch] == nil {
node.children[ch] = &Trie{}
}
node = node.children[ch]
}
node.isEnd = true
}
func (t *Trie) SearchPrefix(prefix string) *Trie {
node := t
for _, ch := range prefix {
ch -= 'a'
if node.children[ch] == nil {
return nil
}
node = node.children[ch]
}
return node
}
func (t *Trie) Search(word string) bool {
node := t.SearchPrefix(word)
return node != nil && node.isEnd
}
func (t *Trie) StartsWith(prefix string) bool {
return t.SearchPrefix(prefix) != nil
}