字符串算法

允我心安 提交于 2020-03-02 00:25:24

KMP

模板:

int kmp[MAXN];   //kmp[i]的基本定义是:在第1-第i位中真前缀与真后缀相同的部分最长是多长 
char a[MAXN],b[MAXN]; //a是文本串,b是模板串,kmp数组是b的next数组 (注意:数组从1开始)
int kmpp(){
	int la,lb,j=0;//j可以看做表示当前已经匹配完的模式串的最后一位的位置
	la=strlen(a+1);
	lb=strlen(b+1);
	for(int i=2;i<=lb;i++){  //自己匹配自己
		while(j&&b[i]!=b[j+1])j=kmp[j];    //找到最长的前后缀重叠长度
	if(b[j+1]==b[i])j++;
	kmp[i]=j;
	}  
	 j=0;
	 int res=0;  
	 for(int i=1;i<=la;i++){   
		while(j>0&&b[j+1]!=a[i])j=kmp[j];          //如果不匹配,则将利用kmp数组往回跳
		if(b[j+1]==a[i]) j++;   
		if(j==lb){    
			//cout<<i-lb+1<<endl;    
			j=kmp[j];    
			res++;   
		}  
	}  
	return res; 
} 

主要是next数组:
next[i] i是前i个字符中,最长的,相同的前后缀,的长度

比如:对于B字符串asdask
它是next数组为:000120

asdask
000120

其中,当i=5时对应第二个s的位置,这时前i个字符为asdas,它的最长的相同的前后缀的长度为2,也就是as。
如要比较A字符串asdasdask
当到第二个s的时候由于下一个字母是d而B字符串中下一个字母是k,于是根据next数组跳到B字符串的第一个s处发现B字符串下一个字母为d,与A字符串下一个字母相同,于是继续。

扩展KMP

模板:

int nxt[N],extend[N]; 
string s,t; 
void getnxt(){
	nxt[0]=t.size();//nxt[0]一定是T的长度
	int now=0;
	while(t[now]==t[1+now]&&now+1<(int)t.size())now++;//这就是从1开始暴力
	nxt[1]=now;
	int p0=1;
	for(int i=2;i<(int)t.size();i++){
		if(i+nxt[i-p0]<nxt[p0]+p0)nxt[i]=nxt[i-p0];//第一种情况
		else{
			//第二种情况
			int now=nxt[p0]+p0-i;
			now=max(now,0);//这里是为了防止i>p的情况 
			while(t[now]==t[i+now]&&i+now<(int)t.size())now++;//暴力 
				nxt[i]=now;
			p0=i;//更新p0 
		}
	} 
}
void exkmp(){
	getnxt();
	int now=0;
	while(s[now]==t[now]&now<min((int)s.size(),(int)t.size()))now++;//暴力 
	extend[0]=now;
	int p0=0;
	for(int i=1;i<(int)s.size();i++){
		if(i+nxt[i-p0]<extend[p0]+p0)extend[i]=nxt[i-p0];//第一种情况 
		else{
			//第二种情况
			int now=extend[p0]+p0-i;
			now=max(now,0);//这里是为了防止i>p的情况 
			while(t[now]==s[i+now]&&now<(int)t.size()&&now+i<(int)s.size())now++;
			extend[i]=now;
			p0=i;//更新p0 
		}
	}
}

有两个字符串S,T,要求输出T与S的每一个后缀的最长公共前缀
输入: S: aaaabaa T: aaaaa
输出: 5 4 3 2 1 (T的nxt数组:T的每一个后缀与T的最长公共前缀长度) 4 3 2 1 0 2 1 (extend数组:S的每一个后缀与T的最长公共前缀长度)

AC自动机

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!