经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
[AC自动机][学习笔记]
来源:cnblogs  作者:wxyww  时间:2018/12/17 9:47:31  对本文有异议

用途

AC自动机适用于一类用多个子串在模板串中匹配的字符串问题。

也就是说先给出一个模板串,然后给出一些子串。要求有多少个子串在这个模板串中出现过。

KMP与trie树

其实AC自动机就是KMP与trie的结合版。或者说是在trie上进行的kmp算法。所以学会kmp和trie是学习AC自动机的基础。

对于上面那类问题。可以对于每个子串都用kmp算法在母串中匹配一次。但是复杂度就成了\(n^2\)

AC自动机

而对于这类问题,AC自动机的实现是先把所有的子串都挂到trie树上,然后在用母串去trie上匹配。

首先往trie上挂子串和普通的trie一样。就像这样

  1. void add() {
  2. int len = strlen(s + 1);
  3. int now = 0;
  4. for(int i = 1;i <= len;++i) {
  5. if(!trie[now][s[i] - 'a']) trie[now][s[i] - 'a'] = ++tot;
  6. now = trie[now][s[i] - 'a'];
  7. }
  8. val[now]++;
  9. }

然后就要建立失配指针。也就是建立起一张trie图,与trie树的区别是这是一张图。(废话)。和kmp类似。如果当前节点下面有x这个字符,那么x的失配指针就指向当前节点失配指针的x孩子。否则,当前节点的儿子就是当前节点失配指针的x孩子。

代码就像这样

  1. void build() {
  2. for(int i = 0;i < 26;++i) if(trie[0][i]) fail[trie[0][i]] = 0,q.push(trie[0][i]);
  3. while(!q.empty()) {
  4. int u = q.front();q.pop();
  5. for(int i = 0;i < 26;++i) {
  6. if(trie[u][i]) fail[trie[u][i]] = trie[fail[u]][i],q.push(trie[u][i]);
  7. else trie[u][i] = trie[fail[u]][i];
  8. }
  9. }
  10. }

查询,那么如何查询呢。其实也很简单,像在trie树上查询一样在这个trie图上查询母串。每查询到一个节点,就不断的沿着他的fail指针跳,然后加上跳到的节点的标记(用来标记当前节点是多少个子串的结尾的标记)。并且标记为访问过了,防止以后重复访问。

代码就像这样

  1. int query() {
  2. int now = 0;
  3. int ans = 0;
  4. int len = strlen(S + 1);
  5. for(int i = 1;i <= len;++i) {
  6. now = trie[now][S[i] - 'a'];
  7. for(int j = now;j && val[j] != -1;j = fail[j]) ans += val[j],val[j] = -1;
  8. }
  9. return ans;
  10. }

其实AC自动机的用途非常广泛,并不是只能处理这一类问题。在各种题目中可以见到他的很多应用。

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号