【hihoCoder】1036 Trie图
题目:http://hihocoder.com/problemset/problem/1036
给一个词典dict,词典中包含了一些单词words。要求判断给定的一个文本串text中是否包含这个字典中的单词words。
相关基础的理解
1. 与用KMP解决的问题的差别
KMP:输入原串S和一个模式串T,判断T是否出现在S中。通过对T计算next数组,避免原串S的回溯。
现在的问题:输入文本串text和多个单词words,判断words中是否有出现在text中。同样希望输入的text不用进行回溯。那么解决方案?
2. trie树识别
把所有的单词构建成trie树,输入ab的识别过程如下:每个节点会通过a/b/c到达下一个节点,当识别到终点(单词的最后一个字母,图中用两个圆表示)时说明整个单词都匹配成功

以上面的trie树为例,如果输入的text串为 ac
| 顺序 | ||||
| 路径 | 1->2 | 2->3 | 1-4 | |
| 过程说明 | a-a匹配成功 | c-b失配 | text在c处失配,下一个用c再去匹配(不回溯) | c-c匹配成功 |
3. trie图(最关键的)
当匹配完成text的前面一部分时(即text'),text'有多个后缀串(不包含text的第一个字母的子串),trie树中可能包含多个text'的后缀。当发生失配时,应该去往这些后缀中最长的一个。
1)最长后缀: text串匹配到3位置(babd)时发生失配(d和e),由3到5( ab-babd)
2)后缀指针:指向它的最长后缀的位置。在trie树中,为每个点添加后缀指针即可构成trie图
3)计算后缀指针:已知父节点的后缀节点,父节点经过字母ch到达子节点。那么子节点的后缀指针应该指向父节点的后缀节点经过当前字母到达的节点(按下图的顺序查找子节点后缀),直到根节点(根节点的后缀为自己)
例:虚线指向的是后缀。当前点为4,4的父节点为3(3-4间为e),3的后缀节点为5,5经过e到达7,所以3的后缀节点为7


源码
代码说明:
1. 节点的结构体中有next[26],表明经过26个字母分别可达的节点
2. 在为每个节点添加后缀指针时,有两种情况:
1)节点经过next[i]有可达位置(子节点):将子节点放入队列(需要计算后缀);计算子节点的后缀=当前点后缀的next[i];
2)节点经过next[i]无可达位置:当前点的next[i]=当前点后缀点的next[i] 避免计算过程中不断地回溯寻找后缀节点
#include <iostream>
#include <queue>
#include <string>
using namespace std; static int nodeCnt = ;
struct Node
{
Node()
{
post = ;
for(int i = ; i < ; i++)
next[i] = ;
post = ;
end = false;
}
int post;//后缀点的位置
int next[];//经过26个字母的下一个可达的位置
bool end;//是否为终点
}nodes[];//最多有1000000个点 //将str添加到trie图中
void build(string str)
{
int strLen = str.length(), i = , current = ;
while(i < strLen)
{
if(nodes[current].next[str[i]-'a'] == )//若当前点经过str[i]可达的位置未设置
nodes[current].next[str[i]-'a'] = ++nodeCnt;
current = nodes[current].next[str[i]-'a'];
i++;
}
nodes[current].end = true;
}
//为trie图中的每个点添加它指向的后缀点位置
void addPost()
{
queue<int> _int_nodes;
_int_nodes.push();
int current;
while(!_int_nodes.empty())
{
current = _int_nodes.front();
_int_nodes.pop();
for(int i = ; i < ; i++)
{
if(nodes[current].next[i] != )
{
_int_nodes.push(nodes[current].next[i]);
if(current != )//不是根结点,需要设置当前点的子节点的后缀=父结点的后缀经过i到达的点
nodes[nodes[current].next[i]].post = nodes[nodes[current].post].next[i];
}
else //nodes[current].next[i] == -1当前点经过i没有可达的
nodes[current].next[i] = nodes[nodes[current].post].next[i];
}
}
} //查找str
bool search(string str)
{
int strLen = str.length(), i = , current = ;
while( i < strLen)
{
if(nodes[nodes[current].next[str[i]-'a']].end)
return true;
current = nodes[current].next[str[i]-'a'];
i++;
}
return false;
}
int main()
{
int cnt;
string str;
cin>>cnt;
while(cnt-- > )
{
cin>>str;
build(str);
}
addPost();
cin>>str;
cout<<(search(str)?"YES":"NO")<<endl;
return ;
}
【hihoCoder】1036 Trie图的更多相关文章
- hihoCoder#1036 Trie图
原题地址 看了这篇博文,总算是把Trie图弄明白了 Runtime Error了无数次,一直不知道为什么,于是写了个脚本生成了一组大数据,发现果然段错误了. 调试了一下午,总算闹明白了,为什么呢? 1 ...
- hihoCoder 1036 Trie图 AC自动机
题意:给定n个模式串和一个文本串,判断文本中是否存在模式串. 思路:套模板即可. AC代码 #include <cstdio> #include <cmath> #includ ...
- hihoCoder week4 Trie图
ac自动机 题目链接 https://hihocoder.com/contest/hiho4/problem/1 参考:https://blog.csdn.net/baidu_30541191/art ...
- 1036 : Trie图 (AC自动机)
题目大意: 输入 n 个目标单词和一个文本串,判断文本串中是否存在某些目标单词. 思路 赤裸裸的 AC自动机. 代码: #include<iostream> #include<cst ...
- hiho一下 第二周&第四周:从Trie树到Trie图
hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihoc ...
- 【hihoCoder 1036】Trie图
看了一下简单的$Trie图$,调模板调啊调一连调了$2h$,最后发现$-'a'$打成$-'A'$了hhh,有种摔键盘的冲动. $Trie图$是$Trie树$上建立“前缀边”,不用再像在$Trie树$上 ...
- HihoCoder第四周:Trie图
第四周的题目是前两周的综合,综合在一个是KMP算法的思想,一个是树的这么一个数据结构. 题目 : Trie图 输入 每个输入文件有且仅有一组测试数据. 每个测试数据的第一行为一个整数N,表示河蟹词典的 ...
- 小菜鸟 菜谈 KMP->字典树->AC自动机->trie 图 (改进与不改进)
本文的主要宗旨是总结自己看了大佬们对AC自动机和trie 图 的一些理解与看法.(前沿:本人水平有限,总结有误,希望大佬们可以指出) KMP分割线--------------------------- ...
- Trie 图
时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本 ...
随机推荐
- ThinkPHP学习总结
ThinkPHP学习总结 网站开发使用的thinkPHP5.0在此总结备查 MVC关系功能图 一.Thinkphp开发规范 l 类 类库.函数文件统一以.php为后缀: 类的文件名均以命名空间定义,并 ...
- main 返回值
int main() 在c中表示返回值时int:也可以不明确给出返回值,默认为int:()表示接受任何参数,main(void)表示不接受任何参数.main(),int main(),main(voi ...
- mui项目中如何使用原生JavaScript代替jquery来操作dom 转自【B5教程网】:http://www.bcty365.com/content-146-3661-1.html
最近在用mui写页面,当然了在移动App里引入jq或zepto这些框架,肯定是极不理性的.原生JS挺简单,为何需要jq?jq的成功当时是因为ie6.7.8.9.10.chrome.ff这些浏览器不兼容 ...
- [原创]用windows7连接windows2003的终端服务器时,出现"由于这台计算机没有远程桌面客户端访问许可证,远程会话被中断"的问题
用windows7连接windows2003的终端服务器时,出现"由于这台计算机没有远程桌面客户端访问许可证,远程会话被中断"的问题,原因是终端服务器授权方式设置为了"每 ...
- swift 的枚举、结构体、类
一.Swift的枚举 枚举是一系相关联的值定义的一个公共的组类型,同时能够让你在编程的时候在类型安全的情况下去使用这些值.Swift中的枚举比OC中的枚举强大得多, 因为Swift中的枚举是一等类型, ...
- xcode8.2 打包问题
如图 在 iOS 到处 ipa包的时候 会有四个选项 PS:证书的账号密码 是需要填写的1.Save for iOS App Store Deployment(部署) sign and packa ...
- hdu 1241 Oil Deposits
#include<cstdio> #include<iostream> #include<algorithm> #include<math.h> #in ...
- 如何安装ipa文件
ipa文件就相当于安卓手机的apkWindows的exe,就是一个程序,只不过ipa是苹果手机的安装包而已,一般苹果的应用程序都是从AppStore下载的,ipa一般用于测试App才会这样安装程序. ...
- 【协议分析】Wireshark 过滤表达式实例
Wireshark 过滤表达式实例 1.wireshark基本的语法 字符 \d 0-9的数字 \D \d的补集(以所以字符为全集,下同),即所有非数字的字符 ...
- iOS 时间的处理
做App避免不了要和时间打交道,关于时间的处理,里面有不少门道,远不是一行API调用,获取当前系统时间这么简单.我们需要了解与时间相关的各种API之间的差别,再因场景而异去设计相应的机制. 时间的形式 ...