From a4187c7bc16a12344da8909e5644a6f479ac4933 Mon Sep 17 00:00:00 2001 From: yk Date: Tue, 13 Feb 2024 20:30:43 +0800 Subject: [PATCH] trie --- config.toml | 2 +- content/posts/2024/02/0213.md | 103 ++++++++++++++++++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) create mode 100644 content/posts/2024/02/0213.md diff --git a/config.toml b/config.toml index 2529727..135e388 100644 --- a/config.toml +++ b/config.toml @@ -351,7 +351,7 @@ auto = false # 是否显示代码块的复制按钮 copy = true # 默认展开显示的代码行数 -maxShownLines = 50 +maxShownLines = 100 # 表格配置 # [params.page.table] # # 是否开启表格排序 diff --git a/content/posts/2024/02/0213.md b/content/posts/2024/02/0213.md new file mode 100644 index 0000000..86dcd29 --- /dev/null +++ b/content/posts/2024/02/0213.md @@ -0,0 +1,103 @@ +--- +title: '0203-前缀树' +date: 2024-02-13T17:54:23+08:00 +lastmod: +tags: [] +series: [] +categories: [] +--- + +## 概念 + +前缀树,也叫字典树,就是一种数据结构,比如有一组字符串 `['abc', 'ab', 'bc', 'bck']`,那么它的前缀树是这样的: + + + +核心:**字符在树的树枝上,节点上保存着信息** + +- 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 也能做到,但是其他点,则是前缀树发挥其本领的绝对领地了。