Featured image of post Implement Trie Prefix Tree

Implement Trie Prefix Tree

208. 实现Trie树

分析

  1. 定义 Trie 树的节点结构
    • 每个节点包含以下信息:
    • is_end:标志当前节点是否是某个单词的结束节点
    • son[26]:一个数组,用于存储指向 26 个小写英文字母子节点的指针。如果某个字母子节点不存在,则为 nullptr
  2. 初始化 Trie
    • 构造函数中初始化根节点 root
  3. 插入单词 insert()
    • 从根节点出发,逐字符检查单词:
    • 如果当前字符对应的子节点不存在,则创建新节点
    • 移动到对应的子节点。
    • 最后将当前节点标记为结束节点 is_end = true
  4. 搜索单词 search()
    • 从根节点出发,逐字符遍历单词:
    • 如果某字符对应的子节点不存在,返回 false
    • 如果全部字符都匹配且最后节点是结束节点,返回 true
    • 否则,返回 false
  5. 检查前缀 startsWith()
    • search 类似,但不需要检查是否是结束节点。只要能完整遍历到前缀,返回 true;否则返回 false

时间复杂度

  • insert()O(n),其中 n 是单词长度,每次需要逐字符插入
  • search()O(n),需要逐字符查找
  • startsWith()O(n),需要逐字符查找

空间复杂度

每个节点存储 26 个指针,整体空间复杂度取决于插入的单词集合的总字符数

C++代码

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
class Trie
{
public:
    // 定义 Trie 树节点类型
    struct Node {
        Node() {
            is_end = false;
            for (int i = 0; i < 26; ++i)
                son[i] = nullptr;
        }

        bool is_end;       // 当前节点是否是某个单词的结束
        Node* son[26];     // 指向 26 个子节点的指针数组
    };

    Node* root;           // Trie 树的根节点

    Trie() {
        root = new Node(); // 初始化根节点
    }

    // 插入单词
    void insert(string word) {
        Node* p = root;
        for (char c : word) {
            int u = c - 'a';          // 计算字符对应的子节点索引
            if (!p->son[u])           // 如果不存在该子节点,则创建新节点
                p->son[u] = new Node();
            p = p->son[u];            // 移动到子节点
        }
        p->is_end = true;             // 标记单词结束
    }

    // 搜索单词
    bool search(string word) {
        Node* p = root;
        for (char c : word) {
            int u = c - 'a';          // 计算字符对应的子节点索引
            if (!p->son[u])           // 如果子节点不存在,返回 false
                return false;
            p = p->son[u];            // 移动到子节点
        }
        return p->is_end;             // 如果最后是结束节点,返回 true
    }

    // 检查前缀
    bool startsWith(string prefix) {
        Node* p = root;
        for (char c : prefix) {
            int u = c - 'a';          // 计算字符对应的子节点索引
            if (!p->son[u])           // 如果子节点不存在,返回 false
                return false;
            p = p->son[u];            // 移动到子节点
        }
        return true;                  // 如果能遍历完整前缀,返回 true
    }
};
Built with Hugo
Theme Stack designed by Jimmy