LeetCode 第 208 题:实现 Trie (前缀树)
字数 1522 2025-10-26 08:43:37

好的,我们来看 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

解题思路

1. 理解 Trie 的结构

Trie 是一棵多叉树,每个节点包含:

  • 一个指向子节点的指针数组(长度 26,对应 26 个小写英文字母)。
  • 一个布尔值 isEnd,表示该节点是否是某个单词的结束节点(即从根节点到该节点的路径构成了一个完整的单词)。

例如,插入 "apple" 后,Trie 的结构如下(* 表示 isEnd = true):

根节点
  -> a -> p -> p -> l -> e*

再插入 "app"

根节点
  -> a -> p -> p* -> l -> e*

app 的最后一个 pisEndtrue,表示 "app" 也是一个完整单词。


2. 设计 Trie 节点类

我们可以先定义节点结构:

  • children: 大小为 26 的数组,初始为 null
  • isEnd: 标记单词结束。

3. 插入操作

从根节点开始,对于要插入的字符串 word 的每个字符:

  1. 计算字符 chchildren 中的索引:index = ch - 'a'
  2. 如果当前节点的 children[index]null,则新建一个节点并指向它。
  3. 移动到子节点,继续处理下一个字符。
  4. 处理完最后一个字符后,将当前节点的 isEnd 设为 true

例子:插入 "and"

  • 根节点:children['a'-'a'] 新建节点 A。
  • 节点 A:children['n'-'a'] 新建节点 N。
  • 节点 N:children['d'-'a'] 新建节点 D。
  • 节点 D:isEnd = true

4. 搜索操作

从根节点开始,对于 word 的每个字符:

  1. 计算索引 index = ch - 'a'
  2. 如果 children[index]null,说明 Trie 中不存在该单词,返回 false
  3. 否则移动到子节点。
  4. 处理完所有字符后,检查当前节点的 isEnd 是否为 true(确保是完整单词,而不是前缀)。

5. 搜索前缀操作

search 类似,但不需要检查 isEnd,只要路径上的每个字符都存在,就返回 true


代码实现(Java)

class Trie {
    private Trie[] children;
    private boolean isEnd;

    public Trie() {
        children = new Trie[26];
        isEnd = false;
    }
    
    public void insert(String word) {
        Trie node = this;
        for (char ch : word.toCharArray()) {
            int index = ch - 'a';
            if (node.children[index] == null) {
                node.children[index] = new Trie();
            }
            node = node.children[index];
        }
        node.isEnd = true;
    }
    
    public boolean search(String word) {
        Trie node = searchPrefix(word);
        return node != null && node.isEnd;
    }
    
    public boolean startsWith(String prefix) {
        return searchPrefix(prefix) != null;
    }

    private Trie searchPrefix(String prefix) {
        Trie node = this;
        for (char ch : prefix.toCharArray()) {
            int index = ch - 'a';
            if (node.children[index] == null) {
                return null;
            }
            node = node.children[index];
        }
        return node;
    }
}

复杂度分析

  • 时间复杂度:插入、搜索、搜索前缀的时间复杂度均为 O(m),其中 m 为字符串长度。
  • 空间复杂度:最坏情况下需要存储所有字符,空间复杂度为 O(26 * m * n),其中 n 为键的个数,m 为平均键长。

总结

Trie 的核心思想是用公共前缀来减少查询时间,常用于处理字符串的快速检索、前缀匹配等场景。掌握 Trie 的基本操作后,可以进一步解决更复杂的问题,如添加通配符、压缩 Trie 等。

好的,我们来看 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 。 解题思路 1. 理解 Trie 的结构 Trie 是一棵多叉树,每个节点包含: 一个指向子节点的指针数组(长度 26,对应 26 个小写英文字母)。 一个布尔值 isEnd ,表示该节点是否是某个单词的结束节点(即从根节点到该节点的路径构成了一个完整的单词)。 例如,插入 "apple" 后,Trie 的结构如下( * 表示 isEnd = true ): 再插入 "app" : app 的最后一个 p 的 isEnd 为 true ,表示 "app" 也是一个完整单词。 2. 设计 Trie 节点类 我们可以先定义节点结构: children : 大小为 26 的数组,初始为 null 。 isEnd : 标记单词结束。 3. 插入操作 从根节点开始,对于要插入的字符串 word 的每个字符: 计算字符 ch 在 children 中的索引: index = ch - 'a' 。 如果当前节点的 children[index] 为 null ,则新建一个节点并指向它。 移动到子节点,继续处理下一个字符。 处理完最后一个字符后,将当前节点的 isEnd 设为 true 。 例子 :插入 "and" : 根节点: children['a'-'a'] 新建节点 A。 节点 A: children['n'-'a'] 新建节点 N。 节点 N: children['d'-'a'] 新建节点 D。 节点 D: isEnd = true 。 4. 搜索操作 从根节点开始,对于 word 的每个字符: 计算索引 index = ch - 'a' 。 如果 children[index] 为 null ,说明 Trie 中不存在该单词,返回 false 。 否则移动到子节点。 处理完所有字符后,检查当前节点的 isEnd 是否为 true (确保是完整单词,而不是前缀)。 5. 搜索前缀操作 与 search 类似,但不需要检查 isEnd ,只要路径上的每个字符都存在,就返回 true 。 代码实现(Java) 复杂度分析 时间复杂度 :插入、搜索、搜索前缀的时间复杂度均为 O(m) ,其中 m 为字符串长度。 空间复杂度 :最坏情况下需要存储所有字符,空间复杂度为 O(26 * m * n) ,其中 n 为键的个数, m 为平均键长。 总结 Trie 的核心思想是 用公共前缀来减少查询时间 ,常用于处理字符串的快速检索、前缀匹配等场景。掌握 Trie 的基本操作后,可以进一步解决更复杂的问题,如添加通配符、压缩 Trie 等。