-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
yk
committed
Feb 13, 2024
1 parent
8a1fcdc
commit a4187c7
Showing
2 changed files
with
104 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
--- | ||
title: '0203-前缀树' | ||
date: 2024-02-13T17:54:23+08:00 | ||
lastmod: | ||
tags: [] | ||
series: [] | ||
categories: [] | ||
--- | ||
|
||
## 概念 | ||
|
||
前缀树,也叫字典树,就是一种数据结构,比如有一组字符串 `['abc', 'ab', 'bc', 'bck']`,那么它的前缀树是这样的: | ||
|
||
<img src='https://cdn.jsdelivr.net/gh/yokiizx/picgo@main/img/202402131753139.png' width='200px'/> | ||
|
||
核心:**字符在树的树枝上,节点上保存着信息** | ||
|
||
- p:通过下接树枝字符的字符串数量. -- 可以查询前缀数量 | ||
- e:以上接树枝字符结尾的字符串数量. -- 可以查询字符串 | ||
|
||
对应的数据结构如下: | ||
|
||
```js | ||
// ### 实现前缀树 lc.208 | ||
class TrieNode { | ||
constructor(pass = 0, end = 0) { | ||
// this.isEnd = false // 这个是另一种实现方式,leetcode 208 题题解,下面这种能多做一种统计 | ||
this.pass = pass // 通过下接树枝字符的字符串数量 | ||
this.end = end // 以上接树枝字符结尾的字符串数量 | ||
this.next = {} // {char: TrieNode} 的 map 集, 字符有限,有些教程也用数组实现 | ||
} | ||
} | ||
class Trie { | ||
constructor() { | ||
this.root = new TrieNode() | ||
} | ||
insert(str) { | ||
if (!str) return | ||
const chars = str.split('') | ||
let node = this.root | ||
for (const s of chars) { | ||
if (!node.next[s]) { | ||
node.next[s] = new TrieNode() | ||
} | ||
node = node.next[s] | ||
node.pass++ | ||
} | ||
node.end++ | ||
} | ||
search(str) { | ||
if (!str) return 0 // 根据实际问题看返回 0 还是 false 值 | ||
const chars = str.split('') | ||
let node = this.root | ||
for (const s of chars) { | ||
if (node.next[s]) { | ||
node = node.next[s] | ||
} else { | ||
return 0 // 根据实际问题看返回 0 还是 false 值 | ||
} | ||
} | ||
return node.end // 根据实际问题 看是返回 end, 还是 返回 true 值 | ||
} | ||
// 有几个以 str 为前缀的字符串。根据实际问题,看是返回 Boolean 还是 number | ||
startWidth(str) { | ||
const chars = str.split('') | ||
let node = this.root | ||
for (const s of chars) { | ||
if (node.next[s]) { | ||
node = node.next[s] | ||
} else { | ||
return 0 | ||
} | ||
} | ||
return node.pass | ||
} | ||
delete(str) { | ||
if (this.search(str) !== 0) { | ||
const chars = str.split('') | ||
let node = this.root | ||
node.pass-- | ||
for (const s of chars) { | ||
node.next[s].pass-- | ||
if (node.next[s].pass == 0) { | ||
node.next[s] = null // 有一个节点的 pass 为 0 的时候,说明后面就都没得了,可以直接把后续置 null 了 | ||
return | ||
} | ||
node = node.next[s] | ||
} | ||
node.end-- | ||
} | ||
} | ||
} | ||
``` | ||
|
||
--- | ||
|
||
前缀树的作用: | ||
|
||
1. 查询字符串 | ||
2. 查询以某个字符串为前缀的字符串有多少个 | ||
3. 自动补完 | ||
|
||
上面两个作用,第一个 hashMap 也能做到,但是其他点,则是前缀树发挥其本领的绝对领地了。 |