Leetcode 题目解析:211. 添加与搜索单词 - 数据结构设计
系列文章:
一 摘要
在考察算法题时,我们往往离不开数据结构。而常见和常用的数据结构,以堆、栈、单/双链表、HashMap、各种二叉树(二叉树、平衡二叉树、搜索二叉树、红黑树)最为常见。另外,像 bitmap 等也比较多,尤其是需要位操作的时候。但还有一些数据结构也会占有一席之地,例如树中的 Trie 树(字典树),在检索类题目中也非常常见。
今天就以一道典型的字典树题目为例211. 添加与搜索单词 - 数据结构设计,再次熟悉一下这个数据结构。
二 题目描述与示例
2.1 描述
leetcode 题目描述:
请你设计一个数据结构,支持 添加新单词 和 查找字符串是否与任何先前添加的字符串匹配 。
实现词典类 WordDictionary :
WordDictionary() 初始化词典对象
void addWord(word) 将 word 添加到数据结构中,之后可以对它进行匹配
bool search(word) 如果数据结构中存在字符串与 word 匹配,则返回 true ;否则,返回 false 。word 中可能包含一些 '.' ,每个 . 都可以表示任何一个字母。
2.2 示例
2.3 基础知识——Trie 树
2.3.1 概念
Trie 树,又称单词查找树,是一种树形结构,哈希树的一种变种。Trie 树的典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。
2.3.2 基本特性
根节点不包含字符,除根节点外每一个节点都只包含一个字符;
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串;
每个节点的所有子节点包含的字符都不相同。
2.3.3 基本操作
Trie 树的基本操作,有查找、插入和删除。在实际应用场景中,删除操作比较少见。
Trie 树可以用 O(∣S∣) 的时间复杂度完成向字典树插入元素 和 查询字符串是否在树中两个操作,其中 ∣S∣ 是插入字符串或查询前缀的长度:
三 题目解析
3.1 描述解析
题目描述已经比较详细,这个就不用特别解释了。就是把输入的字符串逐个放到我们定义的 WordDictionary 结构中,并支持查找。这里实现 3 个方法,构造方法:WordDictionary(),添加方法 addWord(word),查找方法 search(word)。
3.2 示例解析
输入是两个数组,第一个数组是方法数组,按照顺序依次是构造,添加 x3,查找 x4;第二个数组是方法的参数,根据坐标一一对应。输出是上述 8 个方法的执行结果,构造方法和添加方法返回 null,所以我们只要保证添加结果正确和查找判断是否存在方法准确,再封装成数组结构即可。
四 实现
4.1 关键问题
重点在于查找方法,对于搜索单词,从字典树的根结点开始搜索。由于待搜索的单词可能包含点号,因此在搜索过程中需要考虑点号的处理。对于当前字符是字母和点号的情况,分别按照如下方式处理:
如果当前字符是字母,则判断当前字符对应的子结点是否存在,如果子结点存在则移动到子结点,继续搜索下一个字符,如果子结点不存在则说明单词不存在,返回 false;
如果当前字符是点.,由于点号可以表示任何字母,因此需要对当前结点的所有非空子结点继续搜索下一个字符。
重复上述步骤,直到返回 false 或搜索完给定单词的最后一个字符。搜索完给定单词的最后一个字符,也就是搜索到的最后一个结点的 isEnd 标记为 true 时,判定给定的单词存在。特别情况:当搜索到点号时,只要存在一个非空子结点可以搜索到给定的单词,即返回 true。
4.2 代码实现
还是采用 Java 代码实现,包括 Trie 树和字典两个类。
Trie 树:
WordDictionary:
版权声明: 本文为 InfoQ 作者【程序员架构进阶】的原创文章。
原文链接:【http://xie.infoq.cn/article/189842002f03fdc4a88cbb0de】。文章转载请联系作者。
评论