第一次在力扣上刷到"实现 Trie(前缀树)"的时候,我不太服气——不就是一棵树吗?HashMap 也能存字符串,何必折腾。直到后来负责公司评论过滤模块,几十万条敏感词用字符串匹配硬顶,生产环境 CPU 被干到报警,我才彻底想明白一件事:前缀树的价值,不在于它能存什么,而在于它怎么存。力扣热题 100 把这道题排在第 49 位,原题号是 208,要求实现一个 Trie 类,支持 insert、search 和 startsWith 三个方法。看起来简单,却是后面一整套 Trie 类高频题的地基:带通配符的搜索、单词搜索 II、异或最大值、单词替换,全都从这里长出来。这篇文章,我想把一个刷题人从"看懂题解"到"真正会写"的过程完整记录下来。
1. 为什么刷过几百道题,我仍然把这道题当重点
1.1 一次被"自动补全"问倒的面试经历
我记得很清楚,有一场面试,面试官让我现场写一个自动补全的雏形。我理所当然地打开编辑器,打算用一个 HashMap 把所有历史搜索词存起来,然后写个方法遍历 key,凡是 key.startsWith(prefix) 就返回。写了两行,面试官就问了一句:"如果用户输入一个字母,你就全表扫一遍,qps 一上来,扛得住吗?"
那一瞬间我意识到,我从来没有认真想过前缀匹配的性能问题。HashMap 最擅长回答的是"这个完整字符串有没有出现过",但它完全没有办法回答"哪些字符串以某个前缀开头"。你可以把 scan 当成方案,但在真实场景里,那是最笨的一种方案。那次之后,我把 Trie 从头到尾研究了一遍,也终于理解了为什么热题 100 会专门给它留一个位置。
1.2 前缀树到底解决了什么问题,和哈希表比强在哪
Trie 的英文全称是 retrieval tree,意译过来就有"检索"的意思。它的核心思路很简单:把单词拆成一个个字符,逐层存到树上。所有单词共享公共前缀,前缀只存一次。比如插入 apple 和 apply,前面四个字符 a-p-p-l 走的是同一段路径,到最后一个字符才分叉,一个走向 e,一个走向 y。
拿哈希表一对比就非常直观了。HashMap 存的是"完整单词",Trie 存的是"前缀路径"。所以你要查一个完整字符串,两者都能回答;但你要查一个前缀,HashMap 只能把所有
