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/

相关推荐
爱编码的傅同学10 小时前
【今日算法】Leetcode 581.最短无序连续子数组 和 42.接雨水
数据结构·算法·leetcode
wm104311 小时前
代码随想录第四天
数据结构·链表
CoderCodingNo11 小时前
【GESP】C++六级考试大纲知识点梳理, (3) 哈夫曼编码与格雷码
开发语言·数据结构·c++
牛马大师兄11 小时前
数据结构复习 | 什么是数据结构?
数据结构
YuTaoShao11 小时前
【LeetCode 每日一题】2053. 数组中第 K 个独一无二的字符串
算法·leetcode·职场和发展
毅炼12 小时前
hot100打卡——day09
java·leetcode
想逃离铁厂的老铁12 小时前
Day42 >> 188、买卖股票的最佳时机IV + 309.最佳买卖股票时机含冷冻期 + 714.买卖股票的最佳时机含手续费
算法·leetcode·职场和发展
wu_asia12 小时前
方阵对角线元素乘积计算
数据结构·算法
想逃离铁厂的老铁12 小时前
Day43 >> 300.最长递增子序列 + 674. 最长连续递增序列+ 718. 最长重复子数组
数据结构·算法
宵时待雨13 小时前
数据结构(初阶)笔记归纳4:单链表的实现
c语言·开发语言·数据结构·笔记·算法