引言
1. 前缀树
Trie(发音类似 "try")或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
LeetCode 208. 实现 Trie (前缀树),该题可以帮助我们很好的了解前缀树的概念以及应用。
下面这篇入门通俗易懂。
2. 前缀树基本型
那么入门后,我们直接给出前缀树的基本型:
type Trie struct {
isEnd bool
next [26]*Trie
}
func Constructor() Trie {
return Trie{}
}
func (this *Trie) Insert(word string) {
node := this
for _, c := range word {
if node.next[c-'a'] == nil {
node.next[c-'a'] = &Trie{}
}
node = node.next[c-'a']
}
node.isEnd = true
}
func (this *Trie) Search(word string) bool {
node := this
for _, c := range word {
if node.next[c-'a'] == nil {
return false
}
node = node.next[c-'a']
}
return node.isEnd == true
}
func (this *Trie) StartsWith(prefix string) bool {
node := this
for _, c := range prefix {
if node.next[c-'a'] == nil {
return false
}
node = node.next[c-'a']
}
return true
}
首先前缀树适合字符串的搜索,搜索字符会出现分支,就像一棵多叉树一样。
3. 基本型的应用
LeetCode 212. 单词搜索 II
一般字符串搜索可能就用到前缀树,形式比较固定。
我们直接给出题解:
type Trie struct {
word string // 用于记录单词,会用到
next [26]*Trie
}
func (this *Trie) Insert(word string) {
node := this
for _, c := range word {
if node.next[c-'a'] == nil {
node.next[c-'a'] = &Trie{}
}
node = node.next[c-'a']
}
node.word = word
}
var dirs = []struct{ x, y int }{{-1, 0}, {1, 0}, {0, -1}, {0, 1}}
func findWords(board [][]byte, words []string) []string {
t := &Trie{}
for _, word := range words {
t.Insert(word)
}
seen := map[string]bool{}
for i, row := range board {
for j := range row {
dfs(board, seen, t, i, j)
}
}
ans := make([]string, 0, len(seen))
for s := range seen {
ans = append(ans, s)
}
return ans
}
func dfs(board [][]byte, seen map[string]bool, node *Trie, x, y int) {
ch := board[x][y]
node = node.next[ch-'a']
if node == nil {
return
}
if node.word != "" {
seen[node.word] = true
}
board[x][y] = '#'
for _, dir := range dirs {
nx, ny := x+dir.x, y+dir.y
if 0 <= nx && nx < len(board) && 0 <= ny && ny < len(board[0]) && board[nx][ny] != '#' {
dfs(board, seen, node, nx, ny)
}
}
board[x][y] = ch
}