【总结】【字符串】AC自动机&KMP算法

前言:

AC自动机与KMP算法,都是用于优化字符串匹配的算法。
KMP算法应用于单模式串的匹配。
而AC自动机是应用于多模式串的匹配。

但并不意味着KMP算法可以被完全取代(尽管两者的算法思想本质上是一样的)。

KMP算法:

相对而言,KMP算法比较容易一些。

首先,考虑如何暴力匹配?很显然,可以以主串的任意一个位置开头,然后开始匹配,失配后,再找下一个位置开头。

这样的复杂度显然是O(n*m)的。非常低劣。

而KMP算法则是用于优化这个过程的。显然,每次重新匹配时,如果能利用之前匹配的信息,那么就会节约很多时间。这里就要引入fail数组。 f a i l i fail_i faili表示与前缀 i i i拥有相同后缀的,最靠后的位置。这样如果在i号位置失配,那么可以跳到其fail指针的位置,继续匹配。

这样做的复杂度很显然就是O(n+m)的。
板子:

void build(int x){
	int i=0,j=-1;
	fail[0]=-1;
	while(i<len[x]){
		if(j==-1||s1[x][i]==s1[x][j]){
			i++;
			j++;
			fail[i]=j;	
		}
		else
			j=fail[j];
	}
}
void solve(int x){
	int i=0,j=0;
	while(i<m){
		if(j==-1||s[i]==s1[x][j]){
			i++;
			j++;
		}
		else
			j=fail[j];
		if(j==len[x])
			ch[i-len[x]]|=(1<<(x-1));
	}
}

KMP算法实例:

1、BZOJ4974字符串大师
2、BZOJ3670动物园
3、BZOJ4560字符串覆盖
4、BZOJ4820硬币游戏
5、BZOJ2384[Ceoi2011]Match

AC自动机

AC自动机则是将fail指针带到了trie树上。
原理还是一样的。 f a i l i fail_i faili i i i拥有相同后缀的深度最大的点。

每次失配后也是往着 f a i l i fail_i faili跑。

AC自动机算法实例:

1、BZOJ1444有趣的游戏
2、BZOJ1559密码
3、BZOJ4861魔法咒语

板子:

struct node{
	int tag;
	char las;
	node *fail;
	node *ch[30];
}Tree[MAXN];
node* rt=Tree,*ncnt=Tree;
void insert(node *now,char *c,int id){
	if(*c==0){
		now->tag=id;
		return ;
	}
	int d=*c-'a';
	if(now->ch[d]==NULL){
		ncnt++;
		now->ch[d]=ncnt;	
		now->ch[d]->las=*c;
	}
	insert(now->ch[d],++c,id);
}
queue<node *> q;
void build(){
	q.push(rt);
	while(!q.empty()){
		node *now=q.front();
		q.pop();
		for(int i=0;i<26;i++)
			if(now->ch[i]!=NULL){
				node *x=now->fail;
				q.push(now->ch[i]);
				if(now==rt){
					now->ch[i]->fail=now;
					continue;	
				}
				while(x!=rt&&x->ch[i]==NULL)
					x=x->fail;
				if(x->ch[i]==NULL)
					now->ch[i]->fail=rt;
				else
					now->ch[i]->fail=x->ch[i];
			}
	}
}
    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qq_34454069/article/details/83277789
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞