title: 【每日一题】面试高频考点 - LeetCode 208.实现Trie(前缀树)
tags:

  • 每日一题
  • leetcode
  • acwing
  • 算法
    abbrlink: 2c08cb6b
    date: 2021-04-14 16:04:01

LeetCode 208. 实现Trie(前缀树)

思路

这是一道Trie树的标程题,按照Trie树的构建标准写即可,引用Wiki的一段

计算机科学中,trie,又称前缀树字典树,是一种有序),用于保存关联数组,其中的键通常是字符串。与二叉查找树不同,键不是直接保存在节点中,而是由节点在树中的位置决定。一个节点的所有子孙都有相同的前缀,也就是这个节点对应的字符串,而根节点对应空字符串。一般情况下,不是所有的节点都有对应的值,只有叶子节点和部分内部节点所对应的键才有相关的值。

Trie这个术语来自于retrieval。根据词源学,trie的发明者Edward Fredkin把它读作/ˈtriː/ “tree”。[1][2]但是,其他作者把它读作/ˈtraɪ/ “try”。[1][2][3]

在图示中,键标注在节点中,值标注在节点之下。每一个完整的英文单词对应一个特定的整数。Trie可以看作是一个确定有限状态自动机,尽管边上的符号一般是隐含在分支的顺序中的。

键不需要被显式地保存在节点中。图示中标注出完整的单词,只是为了演示trie的原理。

trie中的键通常是字符串,但也可以是其它的结构。trie的算法可以很容易地修改为处理其它结构的有序序列,比如一串数字或者形状的排列。比如,bitwise trie中的键是一串比特,可以用于表示整数或者内存地址。

Trie树的应用

trie树常用于搜索提示。如当输入一个网址,可以自动搜索出可能的选择。当没有完全匹配的搜索结果,可以返回前缀最相似的可能。[4]

C++代码

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

AcWing 142.前缀统计

思路

Trie树的变种应用

C++代码

  1. #include<iostream>
  2. using namespace std;
  3. const int N=1000010;
  4. int n,m;
  5. int son[N][26], cnt[N], idx;
  6. char str[N];
  7. void insert(char *str)
  8. {
  9. int p=0;
  10. for(int i=0;str[i];i++)
  11. {
  12. int u=str[i]-'a';
  13. if(!son[p][u]) son[p][u]=++idx;
  14. p=son[p][u];
  15. }
  16. cnt[p]++;
  17. }
  18. int query(char *str)
  19. {
  20. int p=0, res=0;
  21. for(int i=0;str[i];i++)
  22. {
  23. int u=str[i]-'a';
  24. if(!son[p][u]) break;
  25. p=son[p][u];
  26. res+=cnt[p];
  27. }
  28. return res;
  29. }
  30. int main()
  31. {
  32. cin>>n>>m;
  33. while(n--)
  34. {
  35. cin>>str;
  36. insert(str);
  37. }
  38. while(m--)
  39. {
  40. cin>>str;
  41. cout<<query(str)<<endl;
  42. }
  43. return 0;
  44. }