题目: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] 避免计算过程中不断地回溯寻找后缀节点

  1. #include <iostream>
  2. #include <queue>
  3. #include <string>
  4. using namespace std;
  5.  
  6. static int nodeCnt = ;
  7. struct Node
  8. {
  9. Node()
  10. {
  11. post = ;
  12. for(int i = ; i < ; i++)
  13. next[i] = ;
  14. post = ;
  15. end = false;
  16. }
  17. int post;//后缀点的位置
  18. int next[];//经过26个字母的下一个可达的位置
  19. bool end;//是否为终点
  20. }nodes[];//最多有1000000个点
  21.  
  22. //将str添加到trie图中
  23. void build(string str)
  24. {
  25. int strLen = str.length(), i = , current = ;
  26. while(i < strLen)
  27. {
  28. if(nodes[current].next[str[i]-'a'] == )//若当前点经过str[i]可达的位置未设置
  29. nodes[current].next[str[i]-'a'] = ++nodeCnt;
  30. current = nodes[current].next[str[i]-'a'];
  31. i++;
  32. }
  33. nodes[current].end = true;
  34. }
  35. //为trie图中的每个点添加它指向的后缀点位置
  36. void addPost()
  37. {
  38. queue<int> _int_nodes;
  39. _int_nodes.push();
  40. int current;
  41. while(!_int_nodes.empty())
  42. {
  43. current = _int_nodes.front();
  44. _int_nodes.pop();
  45. for(int i = ; i < ; i++)
  46. {
  47. if(nodes[current].next[i] != )
  48. {
  49. _int_nodes.push(nodes[current].next[i]);
  50. if(current != )//不是根结点,需要设置当前点的子节点的后缀=父结点的后缀经过i到达的点
  51. nodes[nodes[current].next[i]].post = nodes[nodes[current].post].next[i];
  52. }
  53. else //nodes[current].next[i] == -1当前点经过i没有可达的
  54. nodes[current].next[i] = nodes[nodes[current].post].next[i];
  55. }
  56. }
  57. }
  58.  
  59. //查找str
  60. bool search(string str)
  61. {
  62. int strLen = str.length(), i = , current = ;
  63. while( i < strLen)
  64. {
  65. if(nodes[nodes[current].next[str[i]-'a']].end)
  66. return true;
  67. current = nodes[current].next[str[i]-'a'];
  68. i++;
  69. }
  70. return false;
  71. }
  72. int main()
  73. {
  74. int cnt;
  75. string str;
  76. cin>>cnt;
  77. while(cnt-- > )
  78. {
  79. cin>>str;
  80. build(str);
  81. }
  82. addPost();
  83. cin>>str;
  84. cout<<(search(str)?"YES":"NO")<<endl;
  85. return ;
  86. }

【hihoCoder】1036 Trie图的更多相关文章

  1. hihoCoder#1036 Trie图

    原题地址 看了这篇博文,总算是把Trie图弄明白了 Runtime Error了无数次,一直不知道为什么,于是写了个脚本生成了一组大数据,发现果然段错误了. 调试了一下午,总算闹明白了,为什么呢? 1 ...

  2. hihoCoder 1036 Trie图 AC自动机

    题意:给定n个模式串和一个文本串,判断文本中是否存在模式串. 思路:套模板即可. AC代码 #include <cstdio> #include <cmath> #includ ...

  3. hihoCoder week4 Trie图

    ac自动机 题目链接 https://hihocoder.com/contest/hiho4/problem/1 参考:https://blog.csdn.net/baidu_30541191/art ...

  4. 1036 : Trie图 (AC自动机)

    题目大意: 输入 n 个目标单词和一个文本串,判断文本串中是否存在某些目标单词. 思路 赤裸裸的 AC自动机. 代码: #include<iostream> #include<cst ...

  5. hiho一下 第二周&第四周:从Trie树到Trie图

    hihocoder #1014 题目地址:http://hihocoder.com/problemset/problem/1014 hihocoder #1036 题目地址: http://hihoc ...

  6. 【hihoCoder 1036】Trie图

    看了一下简单的$Trie图$,调模板调啊调一连调了$2h$,最后发现$-'a'$打成$-'A'$了hhh,有种摔键盘的冲动. $Trie图$是$Trie树$上建立“前缀边”,不用再像在$Trie树$上 ...

  7. HihoCoder第四周:Trie图

    第四周的题目是前两周的综合,综合在一个是KMP算法的思想,一个是树的这么一个数据结构. 题目 : Trie图 输入 每个输入文件有且仅有一组测试数据. 每个测试数据的第一行为一个整数N,表示河蟹词典的 ...

  8. 小菜鸟 菜谈 KMP->字典树->AC自动机->trie 图 (改进与不改进)

    本文的主要宗旨是总结自己看了大佬们对AC自动机和trie 图 的一些理解与看法.(前沿:本人水平有限,总结有误,希望大佬们可以指出) KMP分割线--------------------------- ...

  9. Trie 图

    时间限制:20000ms 单点时限:1000ms 内存限制:512MB 描述 前情回顾 上回说到,小Hi和小Ho接受到了河蟹先生伟大而光荣的任务:河蟹先生将要给与他们一篇从互联网上收集来的文章,和一本 ...

随机推荐

  1. javaEE基础08

    javaEE基础08 一.继承 特点:继承父类的属性和方法,单继承(多继承) 特性:方法的复写(重写) 比如:人可以养狗 人------>狗:整体和部分(拥有)关系 关键字:extends 结构 ...

  2. 解决绝对定位div position: absolute 后面的<a> Link不能点击

    今天布局的时候,遇到一个bug,当DIV设置为绝对定位时,这个div后面的相对定位的层里面的<a>Link标签无法点击. 网上的解决方案是在绝对定位层里面添加:pointer-events ...

  3. iOS推送小结(证书的生成、客户端的开发、服务端的开发)

    1.推送过程简介 1.1.App启动过程中,使用UIApplication::registerForRemoteNotificationTypes函数与苹果的APNS服务器通信,发出注册远程推送的申请 ...

  4. Servlet引擎Jetty之入门1

    Jetty与tomcat一样,HttpWeb容器,支持实现Servlet规范. 详细介绍参考:https://www.ibm.com/developerworks/cn/java/j-lo-jetty ...

  5. .net学习笔记----HttpRequest,WebRequest,HttpWebRequest区别

    WebRequest是一个虚类/基类,HttpWebRequest是WebRequest的具体实现 HttpRequest类的对象用于服务器端,获取客户端传来的请求的信息,包括HTTP报文传送过来的所 ...

  6. war项目在tomcat上面部署

    1.war包放到webapps根目录下. 2.修改tomcat目录下的conf文件夹里面的的server.xml,在<Host></Host>之间加入: <Context ...

  7. QT编译时 cc1plus进程占用大量内存卡死问题解决

    QT5.7 做一个demo编译时,内存几乎完全消耗,卡死.经尝试发现是添加资源文件过大导致(不知是单个文件过大触发还是文件总共过大触发)的.我的资源文件工136M,单个最大是125M左右. 解决方法是 ...

  8. Delphi容器类之---Tlist,TStringlist,THashedStringlist的效率比较

    转载自:http://www.ylzx8.cn/windows/delphi/73200.html 本人在做一个测试,服务器是IOCP的,我假定最大链接数是50000个. 测试背景:如果每个链接之间的 ...

  9. IIS设置默认主页无效

    服务器系统:Windows server 2008 R2 IIS版本:7.5 IIS中部署一个dotnet framework 3.5的网站应用程序,设置"默认文档"为:index ...

  10. notes

    http://www.cnblogs.com/titicia/p/4388318.html http://blog.csdn.net/kanosword/article/details/5258679 ...