leetcode 链接:208. 实现 Trie (前缀树)

题目

Trie(发音类似 “try”)或者说 前缀树 是一种树形数据结构,用于高效地存储和检索字符串数据集中的键。这一数据结构有相当多的应用情景,例如自动补完和拼写检查。
请你实现 Trie 类:

  • Trie() 初始化前缀树对象。
  • void insert(String word) 向前缀树中插入字符串 word
  • boolean search(String word) 如果字符串 word 在前缀树中,返回 true(即,在检索之前已经插入);否则,返回 false
  • boolean startsWith(String prefix) 如果之前已经插入的字符串 word 的前缀之一为 prefix ,返回 true ;否则,返回 false

wordprefix 仅由小写英文字母组成

示例:

  1. 输入
  2. ["Trie", "insert", "search", "search", "startsWith", "insert", "search"]
  3. [[], ["apple"], ["apple"], ["app"], ["app"], ["app"], ["app"]]
  4. 输出
  5. [null, null, true, false, true, null, true]
  6. 解释
  7. Trie trie = new Trie();
  8. trie.insert("apple");
  9. trie.search("apple"); // 返回 True
  10. trie.search("app"); // 返回 False
  11. trie.startsWith("app"); // 返回 True
  12. trie.insert("app");
  13. trie.search("app"); // 返回 True

解答 & 代码

  1. // Trie 树的节点类(不需要存储节点代表的字母,当前节点是父节点的第几个孩子,就是第几个字母)
  2. struct Node {
  3. vector<Node*> children; // 孩子节点的指针 数组
  4. bool isLeaf; // 当前节点是否是叶子节点(即当前是否代表一个字符串的结束)
  5. // 将 children 数组初始化为包含 26 个孩子节点的指针,且都初始化为 nullptr
  6. // 将当前节点初始化为非叶子节点
  7. Node() : children(26, nullptr), isLeaf(false) {}
  8. };
  9. class Trie {
  10. private:
  11. Node* root; // 根节点
  12. public:
  13. /** Initialize your data structure here. */
  14. Trie() {
  15. root = new Node();
  16. }
  17. /** Inserts a word into the trie. */
  18. void insert(string word) {
  19. Node* cur = root;
  20. int size = word.size();
  21. for(int i = 0; i < size; ++i)
  22. {
  23. int idx = word[i] - 'a';
  24. if(cur->children[idx] == nullptr)
  25. cur->children[idx] = new Node();
  26. cur = cur->children[idx];
  27. }
  28. cur->isLeaf = true; // 将代表最后一个字符的节点设为叶子节点
  29. }
  30. /** Returns if the word is in the trie. */
  31. bool search(string word) {
  32. Node* cur = root;
  33. int size = word.size();
  34. for(int i = 0; i < size; ++i)
  35. {
  36. int idx = word[i] - 'a';
  37. if(cur->children[idx] == nullptr)
  38. return false;
  39. cur = cur->children[idx];
  40. }
  41. return cur->isLeaf;
  42. }
  43. /** Returns if there is any word in the trie that starts with the given prefix. */
  44. bool startsWith(string prefix) {
  45. Node* cur = root;
  46. int size = prefix.size();
  47. for(int i = 0; i < size; ++i)
  48. {
  49. int idx = prefix[i] - 'a';
  50. if(cur->children[idx] == nullptr)
  51. return false;
  52. cur = cur->children[idx];
  53. }
  54. return true;
  55. }
  56. };
  57. /**
  58. * Your Trie object will be instantiated and called as such:
  59. * Trie* obj = new Trie();
  60. * obj->insert(word);
  61. * bool param_2 = obj->search(word);
  62. * bool param_3 = obj->startsWith(prefix);
  63. */

复杂度分析:设每次插入 or 查询的字符串长度为 S;所有插入字符串长度之和为 T

  • 时间复杂度:初始化 O(1),其余操作 O(S)
  • 空间复杂度:O(26T)

执行结果:

执行结果:通过

执行用时:44 ms, 在所有 C++ 提交中击败了 98.06% 的用户
内存消耗:47.1 MB, 在所有 C++ 提交中击败了 36.50% 的用户