AC自动机
来源:互联网 发布:mac电子书导入kindle 编辑:程序博客网 时间:2024/05/29 07:56
- AC自动机
- 简介
- 前提知识
- 问题
- 分析
- AC自动机
- 构建TrieTrie
- 构建fail指针
- 匹配
- 练习
AC自动机
简介
前提知识
KMP 算法
对于问题:
找出长度l 的字符串在长度为m 的字符串中出现次数?KMP 给出了O(l+m) 的做法Trie
有n 个单词,按照单词的前缀来把n 个单词构成一棵树,拥有相同前缀的单词在同一个分支上。
举个例子:
对于单词say,her,he,shr,she
我们构建Trie :
问题
给出
分析
不妨假设每一个单词的长度是
- 原始想法
我们将每一次单词pi 与S 进行匹配,然后判断这个单词在不在该文章中。此时我们可以看出来这样做的复杂度是O(∑ni=1pi∗S)=O(n∗l∗S) 。显然这个复杂度太高了。 - 优化
每一次我们都需要将S 与单词进行匹配,这个时候我们是可以使用KMP 算法来完成。那么我们就可以把整个复杂度降低到O(n∗(l+S)) ,显然这个复杂度要优化很多。 - 再优化
我们是不是真的需要独立地去匹配每一个pi 与S ?如果我们在所有模式串中找到了一定的联系,当S 与其中一个匹配失败时,能够直接(或者说快速地)指向另外一个模式串,那我们将大大降低复杂度。再次利用KMP 思想,我们把所有的模式串构建成一棵Trie 树,然后KMP 中失配时的next 指针进行改成映射到树中某一个节点的fail 指针。这样再进行匹配,那么总的复杂度就会变成O(n∗l+S) 。
AC自动机
n 个模式串构建Trie 复杂度O(n∗l) - 构建
fail 指针O(n∗l) - 进行匹配
O(n∗l+S)
构建Trie :
我们如上图所示建立一棵
void insert(char* str){ int len = strlen(str); int u = rt; FOR(i,0,len){ if(ch[u][str[i]-'a'] == -1){ newnode(); ch[u][str[i]-'a'] = sz; } u = ch[u][str[i]-'a']; } ++ val[u];}
构建fail 指针
我们用
换句话说,如果当前分支为
接下来我们用
首先第一层的所有节点的
以下代码做了做了优化:
void build(){ queue <int> q; FOR(i,0,26){ if(ch[rt][i] == -1){ ch[rt][i] = rt; } else{ fail[ch[rt][i]] = rt; q.push(ch[rt][i]); } } while(!q.empty()){ int u = q.front(); q.pop(); FOR(i,0,26){ if(ch[u][i] == -1){ ch[u][i] = ch[fail[u]][i]; } else{ fail[ch[u][i]] = ch[fail[u]][i]; q.push(ch[u][i]); } } }}
很容易看出复杂度为
匹配
设我们要记录的答案为
以字符串
ch[u][S[i]] 存在,那么继续向下扫描,u 变成ch[u][i] ,S[i] 点变成S[i+1] 。ch[u][S[i]] 不存在,那么u=fail[u] ,继续匹配ch[u][S[i]] ,直到:
2.1 有一个节点匹配,那么u 变成ch[u][i] ,S[i] 点变成S[i+1] 。
2.2 如果没有节点匹配,那么u 变成root ,S[i] 点变成S[i+1] 。
按照以上规则匹配字符串
附上代码:
int query(char* str){ int len = strlen(str); int now = rt; int res = 0; FOR(i,0,len){ now = ch[now][str[i]-'a']; int temp = now; while(temp != rt){ res += val[temp]; val[temp] = 0; temp = fail[temp]; } } return res;}
这里的复杂度就是
练习
HDU 2222 Keywords Search
- AC自动机...
- AC自动机
- AC 自动机
- AC自动机
- AC自动机
- ac自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- AC 自动机
- ac自动机
- AC自动机
- AC自动机
- AC自动机
- AC自动机
- 堆 算法实现
- http消息状态码
- 移植QT5.6到嵌入式开发板(史上最详细的QT移植教程)
- 用java实现一个简单的学生管理系统
- python生成器
- AC自动机
- jsp中页码的实现
- thinkphp路由+伪静态+ index.php
- 1050. 螺旋矩阵(25)
- Node.js 事件驱动获取数据
- Android Studio Module相关笔记
- Idea最常用快捷键
- VMWare使用NAT网络连接总结
- ORACLE 11G 中采用rman备份异机恢复数据库详细过程