Tire

一个字典树只要记住一个定义、两个核心操作就可以了。

son[p][u]:

  1. 其中 p 代表当前节点在树中的索引
  2. u 代表下一个子节点(字符串中的下一位)的值
  3. son[p][u]代表 下一个下一个节点在树中的索引 (0代表没有创建索引)

我们还能发现,Trie和链表的数组实现具有异曲同工之妙。

链表中 ne[idx]代表下一个节点的索引idx代表当前节点的索引

Trie只是将它的子节点扩散成了多个

son[p][u]就相当于 ne[idx][u]

核心操作

开辟一个新节点

  1. if (!son[p][u]) son[p][u] = ++idx;

向下遍历

  1. p = son[p][u]

结合一下

  1. for(int i = 0; str[i]; ++i)
  2. {
  3. u = str[i] - 'a';
  4. if(!son[p][u])son[p][u] = ++idx;
  5. p = son[p][u];
  6. }

这样最终的p遍历出来代表一个特定字符串的结尾。

LeetCode

实现 Trie (前缀树)

需要特别注意的是,Tire的对象实现。

Tire对象实现就比较类似于链表的类实现了。

  1. class Trie {
  2. P head;
  3. int idx = 0;
  4. class P{
  5. boolean is_end;
  6. P[] son = new P[26];
  7. }
  8. /** Initialize your data structure here. */
  9. public Trie() {
  10. head = new P();
  11. }
  12. /** Inserts a word into the trie. */
  13. public void insert(String word) {
  14. int u = 0;
  15. P p = this.head;
  16. for (int i = 0; i < word.length(); i ++){
  17. u = word.charAt(i) - 'a';
  18. if (p.son[u] == null) p.son[u] = new P();
  19. p = p.son[u];
  20. }
  21. p.is_end = true;
  22. }
  23. /** Returns if the word is in the trie. */
  24. public boolean search(String word) {
  25. int u = 0;
  26. P p = this.head;
  27. for (int i = 0; i < word.length(); i ++){
  28. u = word.charAt(i) - 'a';
  29. if (p.son[u] == null) return false;
  30. p = p.son[u];
  31. }
  32. return p.is_end;
  33. }
  34. /** Returns if there is any word in the trie that starts with the given prefix. */
  35. public boolean startsWith(String prefix) {
  36. int u = 0;
  37. P p = this.head;
  38. for (int i = 0; i < prefix.length(); i ++){
  39. u = prefix.charAt(i) - 'a';
  40. if (p.son[u] == null) return false;
  41. p = p.son[u];
  42. }
  43. return true;
  44. }
  45. }
  46. /**
  47. * Your Trie object will be instantiated and called as such:
  48. * Trie obj = new Trie();
  49. * obj.insert(word);
  50. * boolean param_2 = obj.search(word);
  51. * boolean param_3 = obj.startsWith(prefix);
  52. */

或者

  1. class Trie {
  2. int idx = 0;
  3. boolean is_end;
  4. Trie[] son = new Trie[26];
  5. /** Initialize your data structure here. */
  6. public Trie() {
  7. }
  8. /** Inserts a word into the trie. */
  9. public void insert(String word) {
  10. int u = 0;
  11. Trie p = this;
  12. for (int i = 0; i < word.length(); i ++){
  13. u = word.charAt(i) - 'a';
  14. if (p.son[u] == null) p.son[u] = new Trie();
  15. p = p.son[u];
  16. }
  17. p.is_end = true;
  18. }
  19. /** Returns if the word is in the trie. */
  20. public boolean search(String word) {
  21. int u = 0;
  22. Trie p = this;
  23. for (int i = 0; i < word.length(); i ++){
  24. u = word.charAt(i) - 'a';
  25. if (p.son[u] == null) return false;
  26. p = p.son[u];
  27. }
  28. return p.is_end;
  29. }
  30. /** Returns if there is any word in the trie that starts with the given prefix. */
  31. public boolean startsWith(String prefix) {
  32. int u = 0;
  33. Trie p = this;
  34. for (int i = 0; i < prefix.length(); i ++){
  35. u = prefix.charAt(i) - 'a';
  36. if (p.son[u] == null) return false;
  37. p = p.son[u];
  38. }
  39. return true;
  40. }
  41. }
  42. /**
  43. * Your Trie object will be instantiated and called as such:
  44. * Trie obj = new Trie();
  45. * obj.insert(word);
  46. * boolean param_2 = obj.search(word);
  47. * boolean param_3 = obj.startsWith(prefix);
  48. */