字典树基础进阶全掌握(Trie树、01字典树、后缀自动机、AC自动机)
字典树
概述
字典树,又称单词查找树,Trie树,是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。(引自百度百科《字典树》)
光说不懂,上引例——
NKOJ 1934 外地人
你考入大城市沙坪坝的学校, 但是沙坪坝的当地人说着一种很难懂的方言, 你完全
听不懂。 幸好你手中有本字典可以帮你。 现在你有若干个听不懂的方言需要查询字典。
输入格式:
第一行,两个整数n和m。
接下来有n行表示字典的内容,每行表示一条字典的记录。每条记录包含两个空格间隔的单词,第一个单词为英文单词,第二个单词为对应的沙坪坝方言。
接下来有m行,每行一个单词,表示你要查询的沙坪坝方言。
输出格式:
输出m行,每行一个英文单词,表示翻译后的结果。
如果某个单词字典查不到,输出"eh"
样例输入:
5 3
dog ogday
cat atcay
pig igpay
froot ootfray
loops oopslay
atcay
ittenkay
oopslay
样例输出:
cat
eh
loops
注:所有单词都用小写字母表示, 且长度不超过10。
传送门:http://oi.nks.edu.cn/zh/Problem/Details/1934
我们看一下这张图先感受一下Trie树的结构,它是首先建立一个Root根节点,然后在读取后来的字符串的同时,从根节点出发,查找字符串每一位的节点是否存在。若存在,就从这一位出发继续查找下一位;若不存在,就建立这个节点。反复以上过程。注意,Trie树是将字符转换为ASCLL码存取,注意转换。
显然,借用这样的数据结构,我们可以方便存取大量字符串,大幅度优化空间复杂度。
(不知道ASCLL的点这里)
Trie Tree的特点
1. 根节点不包含字符, 除根节点外每一个节点都只包含一个字符。
2. 从根节点到某一节点, 路径上经过的字符连接起来, 为该节点对应的字符串。
3. 在trie树中查找一个关键字的时间和树中包含的结点数无关, 而取决于组成关键字的字符数。 也就是查找字符串s的时间为O(s.length())
4. 如果要查找的关键字可以分解成字符序列且不是很长, 利用Trie树查找速度优于二叉查找树。
如:若关键字长度最大是5, 则利用Trie树, 利用5次比较可以从265=11881376个可能的关键字中检索出指定的关键字。 而利用二叉查找树至少要进行log2265=23.5次比较。
接下来先给出引例题解的main函数部分(部分初始化未给出)——
struct node {
int Num; //如果该节点是一个单词的结尾,记录对应单词的编号
int Next[26]; //儿子节点的编号
}trie[1000001];
string s[100001], a;
int main() {
cin >> n >> m;
for (k = 1; k <= n; k ++){
cin >> s[k] >> a;
Insert(a, k);
}
for (k = 1; k <= m; k ++) {
cin >> a;
ans = Find(a);
if (ans)cout << s[ans];
else cout << "eh" << endl;
}
return 0;
}
接着是两个函数的部分——
void Insert(string c, int k) {
int i, t, len, p = 1;
len = c.length();
for (i = 0; i < len; i ++) {
t = c[i] - 'a';//将字符c[i]转换成值为0到25的数字,比如'a'转换为0,'b'转换为1,‘c’转换为2……
if (trie[p].Next[t] == 0) { //若p没有值为t的儿子
tot ++; //新增一个编号为tot的节点
trie[p].Next[t] = tot; //记下p的值为t的孩子节点的编号
p = trie[p].Next[t]; //p指向新添加的节点
trie[p].Num = 0; //初始化新添加的节点,将其标记为不是单词的结尾
} else p = trie[p].Next[t]; //若p存在值为t的儿子,p指向该儿子,继续讨论
}
trie[p].Num = k; //for循环已执行完,说明第k个单词已加入,在单词结尾做上标记
}
int Find(string c) {
int i, t, len, p = 1;
len = c.length();
for (i = 0; i < len; i ++) {
t = c[i] - 'a';
if (trie[p].Next[t] == 0)return 0; //当前要匹配值为t的字母,若没有则结束
p = trie[p].Next[t]; //若存在值为t的字母,则继续匹配
}
return trie[p].Num; //若for循环执行完毕,说明找到了需要的单词,返回其编号
}
以上的代码几乎就是字典树的模板,在不同的题中main函数或许有所不同,可以借此熟悉一下字典树的工作原理,再酌情修改。
Trie树的应用
(1) 字符串检索
(2) 字符串最长公共前缀
#######提供几道字典树的简单练习:
NKOJ 1931 电话簿
NKOJ 1932 找出克隆人
NKOJ 1933 彩色木条
NKOJ 1935 图书管理员
01字典树
01字典树和普通的字典树原理类似,只不过把插入字符改成了插入二进制串的每一位(0或1)。裸的Trie树可以降低空间复杂度,而01还可以降低时间复杂度。
它与普通的字典树一样先建立Root根节点,但它不存取复杂字符串,而只能存取含有“0”或“1”字符串或数字串。(所以十进制整数可以看做二进制进行存取)以首位为第一个节点建树,按照前面讲解的普通Trie树的工作原理,我们可以得到一个二叉树,而深度由数字范围决定,比如深度为20的01字典树可以进行存取0~221-1的所有数。
后缀自动机
AC自动机
(后续补充)
字典树基础进阶全掌握(Trie树、01字典树、后缀自动机、AC自动机)的更多相关文章
- AC自动机相关Fail树和Trie图相关基础知识
装载自55242字符串AC自动机专栏 fail树 定义 把所有fail指针逆向,这样就得到了一棵树 (因为每个节点的出度都为1,所以逆向后每个节点入度为1,所以得到的是一棵树) 还账- 有了这个东西, ...
- Trie图和Fail树
Trie图和AC自动机的区别 Trie图是AC自动机的确定化形式,即把每个结点不存在字符的next指针都补全了.这样做的好处是使得构造fail指针时不需要next指针为空而需要不断回溯. 比如构造ne ...
- codeforces 842 D. Vitya and Strange Lesson(01字典树+思维+贪心)
题目链接:http://codeforces.com/contest/842/problem/D 题解:像这种求一段异或什么的都可以考虑用字典树而且mex显然可以利用贪心+01字典树,和线段树差不多就 ...
- 【BZOJ2434】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- 【BZOJ2434】【NOI2011】阿狸的打字机(AC自动机,树状数组)
[BZOJ2434]阿狸的打字机(AC自动机,树状数组) 先写个暴力: 每次打印出字符串后,就插入到\(Trie\)树中 搞完后直接搭\(AC\)自动机 看一看匹配是怎么样的: 每次沿着\(AC\)自 ...
- CodeForces -163E :e-Government (AC自动机+DFS序+树状数组)
The best programmers of Embezzland compete to develop a part of the project called "e-Governmen ...
- 从Trie谈到AC自动机
ZJOI的SAM让我深受打击,WJZ大神怒D陈老师之T3是SAM裸题orz...我还怎么混?暂且写篇`从Trie谈到AC自动机`骗骗经验. Trie Trie是一种好玩的数据结构.它的每个结点存的是字 ...
- 【AC自动机&&Trie图】积累
以前KMP和后缀系列(主要是后缀数组,后缀自动机),都刷了一定数量的题,但是对于AC自动机,却有些冷落,罪过. 但是我感觉,在蓝桥杯比赛中AC自动机出现的概率比后缀系列大,简单的会考匹配,稍难一点会考 ...
- AC自动机——1 Trie树(字典树)介绍
AC自动机——1 Trie树(字典树)介绍 2013年10月15日 23:56:45 阅读数:2375 之前,我们介绍了Kmp算法,其实,他就是一种单模式匹配.当要检查一篇文章中是否有某些敏感词,这其 ...
随机推荐
- ASP.NET Core 中间件自定义全局异常处理
目录 背景 ASP.NET Core过滤器(Filter) ASP.NET Core 中间件(Middleware) 自定义全局异常处理 .Net Core中使用ExceptionFilter .Ne ...
- 从0开始搭建kafka客户端
上一节,我们实现了搭建kafka集群.本节我们将从0开始,使用Java,搭建kafka客户端生产消费模型. 1.创建maven项目2.kafka producer3.kafka consumer4.结 ...
- Flutter 拖拽控件Draggable看这一篇就够了
注意:无特殊说明,Flutter版本及Dart版本如下: Flutter版本: 1.12.13+hotfix.5 Dart版本: 2.7.0 Draggable系列组件可以让我们拖动组件. Dragg ...
- 异常 context 包的扫描
异常信息: org.xml.sax.SAXParseException; lineNumber: 7; columnNumber: 55; schema_reference.4: 无法读取方案文档 ' ...
- Flink系列之1.10版流式SQL应用
随着Flink 1.10的发布,对SQL的支持也非常强大.Flink 还提供了 MySql, Hive,ES, Kafka等连接器Connector,所以使用起来非常方便. 接下来咱们针对构建流式SQ ...
- MATLAB神经网络(6) PID神经元网络解耦控制算法——多变量系统控制
6.1 案例背景 6.1.1 PID神经元网络结构 PID神经元网络从结构上可以分为输入层.隐含层和输出层三层,$n$个控制量的PID神经元网络包含$n$个并列的相同子网络,各个子网络间既相互独立,又 ...
- [android]p7-1 fragment学习笔记
本文源自<android权威编程指南第3版>第7章UI fragment与fragment 第7章主要内容是实现一个记录不良行为的APP(部分实现),有列表,有具体的行为内容显示.第7章主 ...
- 记Android R(SDK=30)系统执行UiAutomator1.0异常
最近Android发布了AndroidStudio 3.6稳定版,升级后明显能体验到好多细节的提升,最大的提升莫过于可以创建Android R预览版的模拟器了,并且模拟器可以设置多个尺寸的屏幕.And ...
- java输入输出流操作同一资源实现覆盖引发冲突的解析
一.问题发生的场景 题目:把s.txt中大写转成小写,小写转成大写,空格转成下划线,在输入到文件中覆盖之前的 前面的没有问题,问题出现在后面的覆盖文件上,输入流.输出流要操作同一个文件的问题 二.小白 ...
- 【Weiss】【第03章】练习3.18:检查平衡符号
[练习3.18]用下列语言编写检测平衡符号的程序 a.Pascal ( begin/end, ( ), [ ], { } ). b.C语言( /* */, ( ), [ ], { }). c.解释如何 ...