Trie 树的本质,就是利用字符串之间的公共前缀,将重复的前缀合并在一起
构建 Trie 树的过程比较耗时,对于有 n 个字符的字符串集合而言,需要遍历所有字符,对应的时间复杂度是 O(n),但是一旦构建之后,查询效率很高,如果匹配串的长度是 k,那只需要匹配 k 次即可,与原来的主串没有关系,所以对应的时间复杂度是 O(k),基本上是个常量级的数字。
应用场景:
1.敏感词过滤
2.搜索框联想
PHP
class TrieNode
{
public $value;
public $children = [];
public $isEnd = false;
public function __construct($value)
{
$this->value = $value;
}
}
class Trie
{
public $root;
public function __construct()
{
$this->root = new TrieNode('/');
}
public function add($str)
{
$len = mb_strlen($str);
$parent = $this->root;
for ($i = 0; $i < $len; $i++) {
if ($parent->children[$str[$i]] == null) {
$parent->children[$str[$i]] = new TrieNode($str[$i]);
}
$parent = $parent->children[$str[$i]];
}
$parent->isEnd = true;
}
public function search($str)
{
$len = mb_strlen($str);
$parent = $this->root;
for ($i = 0; $i < $len; $i++) {
if ($parent->children[$str[$i]]->value != $str[$i]) {
return false;
}
$parent = $parent->children[$str[$i]];
}
return $parent->isEnd;
}
}
$strArr = [
'tom',
'tomhaha',
'tom2333',
'jack'
];
$trie = new Trie;
foreach ($strArr as $str) {
$trie->add($ str);
}
var_dump($trie->search('tom'));
GO
package main
import (
"fmt"
)
type TreeNode struct {
value string
isEnd bool
children map[rune]*TreeNode
}
func main() {
strArr := []string{"tom", "tom2333", "tomhaha", "jack"}
root := newTreeNode("/")
for _, s := range strArr {
root.add(s)
}
fmt.Println(root.search("tomhaha"))
}
func (node *TreeNode) add(str string) {
current := node
for _,s := range str {
if current.children[s] == nil {
current.children[s] = newTreeNode(string(s))
}
current = current.children[s]
}
current.isEnd = true
}
func (node *TreeNode) search(str string) bool {
current := node
for _,s := range str {
if current.children[s].value != string(s) {
return false
}
current = current.children[s]
}
return current.isEnd
}
func newTreeNode(value string) *TreeNode {
return &TreeNode{
value: value,
isEnd: false,
children: make(map[rune]*TreeNode),
}
}