LeetCode 211:设计添加与搜索单词的数据结构(Trie + DFS)

这道题要求设计一个 WordDictionary,既能插入单词,又能支持带通配符 . 的搜索。'.' 可以匹配任意一个字母。leetcode

核心难点在于:如何在字典树中优雅地支持通配符搜索。geeksforgeeks+1

题目概述

题目接口如下:leetcode

  • WordDictionary():初始化对象。
  • void addWord(word):把 word 加入数据结构。
  • bool search(word):如果存在任意已添加的字符串能和 word 匹配,则返回 true,否则返回 false;word 可能包含 '.',代表任意字母。

约束:单词长度不超过 25,search 中的 word 最多包含 2 个 '.',总调用次数最多 10^4。这些约束保证了基于 Trie + DFS 的解法可以轻松通过。geeksforgeeks+1

为什么选 Trie

Trie(前缀树)非常适合存储大量字符串并做前缀或精确匹配搜索。algocademy+1

  • 插入一个单词:从根开始,按字符依次向下,如果没有对应子节点就创建,最后的节点标记为"单词结尾"。geeksforgeeks
  • 普通搜索(无通配符):同样逐字符往下走,如果中途某个字符对应的子节点不存在,直接返回 false;如果能走到最后一个字符,并且当前节点是"单词结尾",返回 true。geeksforgeeks

在本题中,插入完全是标准 Trie 操作,难点都在搜索的 . 处理上。github+1

搜索逻辑:关键在 . 的处理

搜索函数的整体思路是:对字符串做 DFS 搜索。algo+1

设一个递归函数:

text 复制代码
bool dfs(trie_node *node, const char *word, int idx)

表示"当前在 node 节点,从 word[idx] 开始匹配剩余字符串,能否成功"。algo

分两种情况:

  1. 当前字符是普通字母 c

    • 在当前节点的子节点中找到字符 c 对应的 child。
    • 如果不存在,直接返回 false。
    • 如果存在,递归到这个 child,索引 idx + 1。
  2. 当前字符是 '.'

    • 无法确定下一步走哪条边,需要遍历当前节点的所有子节点。
    • 对每一个子节点 child 调用 dfs(child, word, idx + 1)。
    • 只要有一个返回 true,当前就可以返回 true;如果所有子节点都失败,返回 false。geeksforgeeks+1

当 idx 到达字符串末尾时,如果当前节点是一个单词结尾,返回 true,否则返回 false。algo

自定义 get_child_node 接口设计

你设计的接口大致是:

c 复制代码
void get_child_node(trie_node_t *parent_node,
                    trie_node_t **children,
                    int *children_num,
                    char key);

行为约定为:

  • 如果 key 不是 '.':
    • 能找到对应子节点:children 返回该 child,children_num = 1。
    • 找不到:children = NULL,children_num = 0。
  • 如果 key 是 '.':
    • children 返回"所有子节点"组成的链表头指针。
    • children_num 为子节点个数。

在 search / dfs 里就可以这样用:

  • 普通字符:get_child_node 只返回 0 或 1 个 child,直接判断是否存在并继续递归。
  • '.':get_child_node 返回一个 child 链表,上层遍历这 children_num 个 child,对每个 child 递归匹配剩余子串。

这个设计本质上就是把"根据 key 拿到可能的 child 集合"的逻辑封装到一个函数里,和主流的 Trie + DFS 解法在思想上是完全一致的,只是具体 API 风格不同。okc1.github+1

DFS 还是 BFS?

在这题里,主流解法都是 DFS,原因有:

  • 每条路径最多 25 个字符,递归深度很浅;DFS 写法简洁直观。github+1
  • '.' 的分支数有限,DFS 回溯成本可控。

理论上也可以用 BFS:队列里存 (node, idx) 状态,每次出队一个状态,根据当前字符扩展到下一层节点;但代码会比 DFS 啸嗦一些,所以一般不作为首选。accidentalfactors+1

更一般地说,Trie 自身既可以 DFS 遍历,也可以 BFS 遍历:

  • 自动补全需要"枚举某前缀下所有单词"时,大家通常用 DFS,但如果需要按长度层级排序,也可以选 BFS。ali-ibrahim137.github+1

小结

  • 数据结构:用 Trie 存所有单词。
  • 搜索策略:用 DFS 处理通配符 '.',在出现 '.' 的位置展开所有子节点分支。
  • 接口设计:把"取子节点集合"的逻辑封装成 get_child_node,对于普通字符返回 0/1 个 child,对于 '.' 返回所有 child 链表,上层统一用 DFS 处理。

从算法本质上看,这种写法与 LeetCode 官方推荐的 "Trie + DFS" 解法是一致的,足以通过所有测试用例。leetcode+2

https://leetcode.com/problems/design-add-and-search-words-data-structure/

相关推荐
Dream it possible!2 小时前
LeetCode 面试经典 150_图的广度优先搜索_蛇梯棋(93_909_C++_中等)(广度优选搜索)
c++·leetcode·面试·广度优先
资深web全栈开发2 小时前
LeetCode 3578:统计极差最大为 K 的分割方式数 - 深入浅出指南
算法·leetcode·前缀和·动态规划·滑动窗口
FuckPatience2 小时前
C# BinarySearch 的返回值
开发语言·数据结构·c#
代码雕刻家2 小时前
1.8.课设实验-数据结构-哈夫曼树的建立与应用
c语言·数据结构
alphaTao2 小时前
LeetCode 每日一题 2025/12/1-2025/12/7
数据库·算法·leetcode
苏小瀚2 小时前
[算法]---分治-快排和归并
java·算法·leetcode
Jac_kie_層樓2 小时前
力扣hot100刷题记录(12.1)
算法·leetcode·职场和发展
无限进步_2 小时前
寻找数组中缺失数字:多种算法详解与比较
c语言·开发语言·数据结构·算法·排序算法·visual studio
xu_yule2 小时前
数据结构(4)链表概念+单链表实现
数据结构·算法·链表