AC自动机

Ac自动机就是在一个字符串中,查找多个给出多个模式串,查找匹配。
多次kmp字符串匹配?在给出模式串数目特别大的情况下,即便是kmp也会超时,因此,我们这里有了ac自动机,即在tire上kmp,只需遍历一遍原字符串就能找出所有匹配。
tire树又称字典树,利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较 不会的看这里
我们需要的是在trie上kmp。

首先是建立一个trie树,这里就不过多赘述

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct tree{
	int vis[26];
	int end;
	int fail;
}ac[10000005];
int cnt;
char s[10000005];
int queue[10000000],start,end;

void build(int n){
	int i,j,k,l,now;
	for(i=0;i<n;i++){
		scanf("%s",s);
		l=strlen(s),now=0;
		for(j=0;j<l;j++){
			if(ac[now].vis[s[j]-'a']==0)
			ac[now].vis[s[j]-'a']=++cnt;
			now=ac[now].vis[s[j]-'a'];
		}
		ac[now].end+=1;
	}
}

然后就是寻匹配失败的回溯位置,即fail(看毛片) 。

先来定义一下: 匹配失败,即该节点不存在要查找的子节点。(这是容易混淆的一点)
fail指该结点匹配失败后,回溯到的结点 暂时不懂没关系

  • 首先是根结点,匹配失败,则fail仍指向根结点
  • 再对根结点的子节点进行讨论,若子节点匹配失败,则需要回到根结点重新匹配,fail指向根结点。
  • 再对已经找到fail的结点,遍历他们的子节点。若某个子结点 i 匹配失败,将vis[i] 置为当前结点的fail的vis[i],即回溯过程。 若某个结点 i 的子节点存在,则将该子节点的fail置为原结点的fail的vis[i]。

第三步可能很难理解,这里给出一个结论,结合着这些结论,应该就不难理解。

每一个结点的fail所代表的字符串,是这个结点所代表的字符串的最大后缀匹配(kmp思想)。
数学归纳法证明:
首先,所有的根结点满足
假设第k层满足
对k+1层的某个结点i,它的fail是在第k层父节点的fail的vis[i],父节点的fail是它的最大后缀匹配

  • 若fail的vis[i] 存在,那么k+1层的fail即第k+1最大后缀匹配
  • 若fail的vis[i]不存在,fail的vis[i]存储的是fail的fail的vis[i],即fail的最大后缀的匹配的vis[i],若vis[i]存在,则是当前节点的最大后缀匹配,若不存在,则可一直向下,直到0,在这个过程中,可以保证不存在更长的最大后缀匹配。
    这里是代码
void get_fail(){
	int n,i,j,k,u;
	for(i=0;i<26;++i){//第二层 
		if(ac[0].vis[i]!=0){
			ac[ac[0].vis[i]].fail=0;//不匹配则指向0 
		 queue[end++]=ac[0].vis[i];//加入队列 		
		
		} 

	}
	while(end!=start){
		u=queue[start++];
		for(i=0;i<26;i++){
			if(ac[u].vis[i]==0)//若第i个不存在,则相当于匹配失败,访问u的fail的i 
			ac[u].vis[i]=ac[ac[u].fail].vis[i];
			else ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i],queue[end++]=ac[u].vis[i];// 存在该节点 
		}
	}
	
}

如果上面理解了,下面的匹配过程也挺好理解
我们要查找模式串在给定字符串中出现种类个数
遍历字符串中的每一个字符,沿着建好的树走,对于到达的每一个结点,考虑到该结点字符串可能是别的字符串的后缀,因此,一直遍历fail结点。直到为根结点,将所有可能的结点都遍历完即可。
这里就是全部代码了

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
struct tree{
	int vis[26];
	int end;
	int fail;
}ac[10000005];
int cnt;
char s[10000005];
int queue[10000000],start,end;

void build(int n){
	int i,j,k,l,now;
	for(i=0;i<n;i++){
		scanf("%s",s);
		l=strlen(s),now=0;
		for(j=0;j<l;j++){
			if(ac[now].vis[s[j]-'a']==0)
			ac[now].vis[s[j]-'a']=++cnt;
			now=ac[now].vis[s[j]-'a'];
		}
		ac[now].end+=1;
	}
}
void get_fail(){
	int n,i,j,k,u;
	for(i=0;i<26;++i){//第二层 
		if(ac[0].vis[i]!=0){
			ac[ac[0].vis[i]].fail=0;//不匹配则指向0 
		 queue[end++]=ac[0].vis[i];//加入队列 		
		
		} 

	}
	while(end!=start){
		u=queue[start++];
		for(i=0;i<26;i++){
			if(ac[u].vis[i]==0)//若第i个不存在,则相当于匹配失败,访问u的fail的i 
			ac[u].vis[i]=ac[ac[u].fail].vis[i];
			else ac[ac[u].vis[i]].fail=ac[ac[u].fail].vis[i],queue[end++]=ac[u].vis[i];// 存在该节点 
		}
	}
	
}
int ac_match(){
	int l=strlen(s),i,j,now=0,count=0;
	for(i=0;i<l;i++){
	now=ac[now].vis[s[i]-'a'];
	for(int t=now;t&&ac[t].end!=-1;t=ac[t].fail)count+=ac[t].end,ac[t].end=-1;
	
	}
	return count;
	
}
int main(){
	int n;
	scanf("%d",&n);
	build(n);
	get_fail();
	scanf("%s",s);
	printf("%d",ac_match());

}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Python AC自动机是一个用于字符串匹配的算法,它可以高效地在一段文本中查找多个预定义的模式。它的实现可以使用多种库,其中包括ac自动机python和ahocorasick-python。 ac自动机python是一个对标准的ac自动机算法进行了完善和优化的实现,适用于主流的Python发行版,包括Python2和Python3。它提供了更准确的结果,并且可以通过pip进行安装,具体的安装方法可以参考官方文档或者使用pip install命令进行安装。 ahocorasick-python是另一个实现AC自动机的库,它也可以用于Python2和Python3。你可以通过官方网站或者GitHub源码获取更多关于该库的信息和安装指南。 对于AC自动机的使用,一个常见的例子是在一段包含m个字符的文章中查找n个单词出现的次数。要了解AC自动机,需要有关于模式树(字典树)Trie和KMP模式匹配算法的基础知识。AC自动机算法包括三个步骤:构造一棵Trie树,构造失败指针和模式匹配过程。在构造好AC自动机后,可以使用它来快速地在文本中查找预定义的模式,并统计它们的出现次数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [ahocorasick-python:AC自动机python的实现,并进行了优化。 主要修复了 查询不准确的问题](https://download.csdn.net/download/weixin_42122986/18825869)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Python实现多模匹配——AC自动机](https://blog.csdn.net/zichen_ziqi/article/details/104246446)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值