Trie的核心思想是空间换时间。利用字符串的公共前缀来降低查询时间的开销以达到提高效率的目的。

Trie 的应用场景: 一次建树,多次查询

前缀树的3个基本性质:

  1. 根节点不包含字符,除根节点外每一个节点都只包含一个字符。
  2. 从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串。
  3. 每个节点的所有子节点包含的字符都不相同。

前缀树查询和哈希查询的比较(示相对情况而定):
通常字典树的查询时间复杂度是O(logL),L是字符串的长度。

适用场景:

  1. 字符串的快速检索
  2. 字符串排序
  3. 最长公共前缀
  4. 自动匹配前缀显示后缀

208. 实现 Trie (前缀树)

三个单词 “sea”,”sells”,”she” 的 Trie

image.png
image.png

  1. class TrieNode {
  2. children;
  3. isEnd;
  4. constructor() {
  5. this.children = new Array(26);
  6. this.isEnd = false;
  7. }
  8. }
  9. class Trie {
  10. root;
  11. constructor() {
  12. this.root = new TrieNode();
  13. }
  14. insert(word: string): void {
  15. let head = this.root;
  16. for (let char of word) {
  17. let index = char.charCodeAt(0) - 97;
  18. if (!head.children[index]) {
  19. head.children[index] = new TrieNode();
  20. }
  21. head = head.children[index];
  22. }
  23. head.isEnd = true;
  24. }
  25. search(word: string): boolean {
  26. let head = this.searchPrefix(word);
  27. return head != null && head.isEnd;
  28. }
  29. startsWith(prefix: string): boolean {
  30. return this.searchPrefix(prefix) != null;
  31. }
  32. private searchPrefix(prefix: string) {
  33. let head = this.root;
  34. for (let char of prefix) {
  35. let index = char.charCodeAt(0) - 97;
  36. if (!head.children[index]) return null;
  37. head = head.children[index];
  38. }
  39. return head;
  40. }
  41. }

720. 词典中最长的单词

692. 前K个高频单词

练习:

面试题 17.17. 多次搜索

LC练习:

677. 键值映射

返回所有以该前缀 prefix 开头的键 key 的值的总和

676. 实现一个魔法字典

判定能否只将字符串中 一个 字母换成另一个字母,使得所形成的新字符串能够与字典中的任一字符串匹配

421. 数组中两个数的最大异或值