Trie

什么是Trie

  • Trie字典树/前缀树的直观感受

image.png

  • Trie只用来处理字符串

image.png

其中蓝色就是单词结尾节点。

  1. class Node{
  2. boolean isWord; //表示该字母是否是单词的结尾
  3. Map<char,Node> next;
  4. }

Trie基础

  1. public class Trie {
  2. private class Node{
  3. public boolean isWord;//标记该字符是否是单词结尾
  4. public TreeMap<Character,Node> next;
  5. public Node(boolean isWord){
  6. this.isWord=isWord;
  7. next=new TreeMap<>();
  8. }
  9. public Node(){
  10. this(false);
  11. }
  12. }
  13. private Node root;
  14. private int size;
  15. public Trie(){
  16. root=new Node();
  17. size=0;
  18. }
  19. //获取Trie中存储的单词数量
  20. public int getSize(){
  21. return size;
  22. }
  23. //向Trie中添加一个新单词word
  24. public void add(String word){
  25. Node cur=root;
  26. for(int i=0;i<word.length();i++){
  27. char c=word.charAt(i);
  28. if(cur.next.get(c)==null){
  29. cur.next.put(c,new Node());
  30. }
  31. cur=cur.next.get(c);
  32. }
  33. //循环结束后,cur不一定是叶子节点,比如Trie中已经有 "panda",此时add("pan"),
  34. // cur指向'n'节点,显然'n'不是叶子节点,那么就要标记为结束位置
  35. if(!cur.isWord){
  36. //!cur.isWord 表示该节点未被标识为结束位置
  37. cur.isWord=true;
  38. size++;
  39. }
  40. }
  41. }

Trie字典树查询

  1. //查询单词是否在Trie中
  2. public boolean contains(String word){
  3. Node cur=root;
  4. for(int i=0;i<word.length();i++){
  5. char c=word.charAt(i);
  6. if(cur.next.get(c)==null){
  7. return false;
  8. }
  9. cur=cur.next.get(c);
  10. }
  11. //注意:即使循环结束了,也不一定能确定该单词就在Trie中
  12. //如果Trie中已经有单词"panda",此时要查询"pan"
  13. //循环结束后,cur此时指向'n'节点,'n'节点不是结尾节点,即"pan"不在Trie中
  14. return cur.isWord;
  15. }

Trie字典树前缀查询

  1. //查询是否在Trie中存在以prefix为前缀的单词
  2. public boolean isPrefix(String prefix){
  3. Node cur=root;
  4. for(int i=0;i<prefix.length();i++){
  5. char c=prefix.charAt(i);
  6. if(cur.next.get(c)==null){
  7. return false;
  8. }
  9. cur=cur.next.get(c);
  10. }
  11. //注意:循环结束后,cur不管是单词的结尾节点还是非结尾节点,都成立
  12. //单词本身就是该单词的前缀
  13. return true;
  14. }
  • LeetCode 208题 实现Trie字典树
  1. class Trie {
  2. private class Node{
  3. public boolean isWord;//标记该字符是否是单词结尾
  4. public TreeMap<Character,Node> next;
  5. public Node(boolean isWord){
  6. this.isWord=isWord;
  7. next=new TreeMap<>();
  8. }
  9. public Node(){
  10. this(false);
  11. }
  12. }
  13. private Node root;
  14. /** Initialize your data structure here. */
  15. public Trie() {
  16. root=new Node();
  17. }
  18. /** Inserts a word into the trie. */
  19. public void insert(String word) {
  20. Node cur=root;
  21. for(int i=0;i<word.length();i++){
  22. char c=word.charAt(i);
  23. if(cur.next.get(c)==null){
  24. cur.next.put(c,new Node());
  25. }
  26. cur=cur.next.get(c);
  27. }
  28. //循环结束后,cur不一定是叶子节点,比如Trie中已经有 "panda",此时add("pan"),
  29. // cur指向'n'节点,显然'n'不是叶子节点,那么就要标记为结束位置
  30. if(!cur.isWord){
  31. //!cur.isWord 表示该节点未被标识为结束位置
  32. cur.isWord=true;
  33. }
  34. }
  35. /** Returns if the word is in the trie. */
  36. public boolean search(String word) {
  37. Node cur=root;
  38. for(int i=0;i<word.length();i++){
  39. char c=word.charAt(i);
  40. if(cur.next.get(c)==null){
  41. return false;
  42. }
  43. cur=cur.next.get(c);
  44. }
  45. //注意:即使循环结束了,也不一定能确定该单词就在Trie中
  46. //如果Trie中已经有单词"panda",此时要查询"pan"
  47. //循环结束后,cur此时指向'n'节点,'n'节点不是结尾节点,即"pan"不在Trie中
  48. return cur.isWord;
  49. }
  50. /** Returns if there is any word in the trie that starts with the given prefix. */
  51. public boolean startsWith(String prefix) {
  52. Node cur=root;
  53. for(int i=0;i<prefix.length();i++){
  54. char c=prefix.charAt(i);
  55. if(cur.next.get(c)==null){
  56. return false;
  57. }
  58. cur=cur.next.get(c);
  59. }
  60. //注意:循环结束后,cur不管是单词的结尾节点还是非结尾节点,都成立
  61. //单词本身就是该单词的前缀
  62. return true;
  63. }
  64. }

Trie字典树和简单的模式匹配

LeetCode 211

  1. class WordDictionary {
  2. private class Node{
  3. public boolean isWord;//标记该字符是否是单词结尾
  4. public TreeMap<Character,Node> next;
  5. public Node(boolean isWord){
  6. this.isWord=isWord;
  7. next=new TreeMap<>();
  8. }
  9. public Node(){
  10. this(false);
  11. }
  12. }
  13. private Node root;
  14. /** Initialize your data structure here. */
  15. public WordDictionary() {
  16. root=new Node();
  17. }
  18. /** Adds a word into the data structure. */
  19. public void addWord(String word) {
  20. Node cur=root;
  21. for(int i=0;i<word.length();i++){
  22. char c=word.charAt(i);
  23. if(cur.next.get(c)==null){
  24. cur.next.put(c,new Node());
  25. }
  26. cur=cur.next.get(c);
  27. }
  28. //循环结束后,cur不一定是叶子节点,比如Trie中已经有 "panda",此时add("pan"),
  29. // cur指向'n'节点,显然'n'不是叶子节点,那么就要标记为结束位置
  30. if(!cur.isWord){
  31. //!cur.isWord 表示该节点未被标识为结束位置
  32. cur.isWord=true;
  33. }
  34. }
  35. /** Returns if the word is in the data structure. A word could contain the dot character '.' to represent any one letter. */
  36. public boolean search(String word) {
  37. return match(root,word,0);
  38. }
  39. //判断word在index位置是否匹配
  40. private boolean match(Node node,String word,int index){
  41. if(index==word.length()){
  42. return node.isWord;
  43. }
  44. char c=word.charAt(index);
  45. if(c!='.') {
  46. //c是小写字母
  47. if (node.next.get(c) == null) {
  48. return false;
  49. }
  50. return match(node.next.get(c), word, index + 1);
  51. }else{
  52. //遍历所有从以该点为根节点的子树
  53. for(char nextChar:node.next.keySet()){
  54. if(match(node.next.get(nextChar),word,index+1)){
  55. return true;
  56. }
  57. }
  58. return false;
  59. }
  60. }
  61. }

Trie字典树和字符串映射

LeetCode 677