树、BST 与 Trie · HTML
数学 / 逻辑形态
根代表空前缀;边标字符,根到节点路径拼成一个前缀。节点含 children 映射与 terminal 标记/载荷。insert 逐字符建边;search 走完整路径并检查 terminal;starts_with 只需路径存在。
识别信号
- 大量字符串共享前缀并被反复查询。
- 需要区分完整词存在与前缀存在。
- 字符 DFS 要同时匹配词典中许多词。
- 查询复杂度应依赖查询长度而非词典总词数。
- 需要自动补全、最长前缀或词典剪枝。
容易误判的相似信号
| Signal | Why it is different |
|---|
| 只查一个固定模式 | KMP 等单模式算法更省内存。 |
| 只做精确集合成员查询 | hash set 平均 O(L) 且内存/实现更简单;Trie 的优势在前缀结构。 |
| 超大稀疏字符集用固定数组 | 每节点分配完整 alphabet 会浪费巨大空间,应使用 map 或压缩 Trie。 |
核心不变量
任一 Trie 节点对应唯一前缀;其 children 恰表示字典中该前缀后可能出现的下一字符,terminal 只在完整词末端为真。
状态、转移与处理顺序
| Item | Definition |
|---|
| State | 当前 Trie 节点、下一个字符位置,以及节点 children/terminal/可选载荷。 |
| Transition | 读取字符 ch 后沿 children[ch] 前进;插入时缺边则创建;搜索时缺边立即失败。 |
| Frontier / order | 单查询是一条前缀路径;与网格/回溯组合时,Trie 节点把候选词集合压缩为当前前缀的子树。 |
Python 骨架
class TrieNode:
def __init__(self):
self.children = {}
self.terminal = False
class Trie:
def __init__(self):
self.root = TrieNode()
def insert(self, word):
node = self.root
for ch in word:
node = node.children.setdefault(ch, TrieNode())
node.terminal = True
def _walk(self, text):
node = self.root
for ch in text:
if ch not in node.children: return None
node = node.children[ch]
return node
def search(self, word):
node = self._walk(word)
return bool(node and node.terminal)
def starts_with(self, prefix):
return self._walk(prefix) is not None
正确性思路
- 插入按字符创建/复用边,归纳后根到末节点路径恰拼出 word,并标 terminal。
- walk 每步只沿与下一个字符相同的边;若缺边,字典中不可能有该前缀。
- 走完整路径后 terminal 区分‘该路径只是更长词前缀’与‘完整词已插入’,所以两类查询正确。
复杂度
| Time | Space | Parameters |
|---|
| insert/search/prefix 为 O(L) 期望(children 为哈希映射) | O(T),T 为所有不同前缀字符节点数,最坏为总字符数 | L 为操作字符串长度,T 为去重后的前缀节点数。 |
边界条件
- 空字符串是否为词
- 大小写/Unicode 规范化
- 重复插入
- 删除后共享前缀
- terminal 与有 children 可同时存在
- 递归列出补全结果
错误模式
| Pattern | Why it fails / fix |
|---|
| search 只检查路径存在 | 会把仅为前缀的字符串误判为完整词;必须检查 terminal。 |
| starts_with 检查 terminal | 前缀无需自身是完整词。 |
| 固定 26 子数组硬套所有字符集 | 字符域不小/不连续时浪费空间或索引错误。 |
| 回溯中每次从 root 重走前缀 | 应把当前 Trie node 随 DFS 传递,使每次只走一条边。 |
选择与排除规则
- 只有前缀查询/共享剪枝价值明显时选择 Trie。
- 字符域小而密可数组,大而稀用 map。
- 明确 terminal 与 prefix 两种语义。
- 与回溯组合时状态携带 node 而非完整前缀重查。
相关模板
原创微型例子
| 环节 | 内容 |
|---|
| Result | search('tea') 与 starts_with('te') 为真,search('te') 为假。 |
| Setup | 插入 'tea' 与 'team'。 |
| Trace | 两词共享 t-e-a 三个节点;a 节点 terminal=True 且仍有 child m。 |
Recall prompts
我的补充