KMP算法模版

const int maxn=1e6+5;
int nx[maxn];
//	 nx[] 的含义:x[i-nx[i]...i-1]=x[0...nx[i]-1] 
// 	 nx[i] 为满足 x[i-z...i-1]=x[0...z-1] 的最大 z 值(就是 x 的自身匹配) 
void getnx(char *x) {
	int i,j;
	int m=strlen(x);
	j=nx[0]=-1;
	i=0;
	while (i<m) {
		while ( -1!=j && x[i]!=x[j]) j=nx[j];
		nx[++i]=++j;
	}
}

//输出多次出现的位置
void kmp(char *x, char *y) { //x为匹配串,y为模式串
	int n=strlen(x);
	int m=strlen(y);
	int i=0,j=0;
	getnx(y);
	while (i<n && j<m) {
		while (-1!=j && x[i]!=y[j]) j=nx[j];
		i++;
		j++;
		if (j==m) {
			cout<<i-j+1<<endl;
			j=nx[j];
		}
	}
}
//输出第一次出现的位置
int kmp(char *x, char *y) { //x为匹配串,y为模式串
	int n=strlen(x);
	int m=strlen(y);
	int i=0,j=0;
	getnx(y);
	while (i<n && j<m) {
		while (-1!=j && x[i]!=y[j]) j=nx[j];
		i++;
		j++;
	}
	if (j==m)
		return i-j;
	else return -1;
}
//返回y在x中出现的次数,可以重叠
int kmp_count(char *x, char *y){
	int n=strlen(x);
	int m=strlen(y);
	int i=0,j=0,ans=0;
	getnx(y);
	while (i<n){
		while (-1!=j && x[i]!=y[j]) j=nx[j];
		i++;
		j++;
		if (j>=m){
			ans++;
			j=nx[j];  //如果不可重叠,将此处改为  j=0;
		}
	}
	return ans;
}
//输出nx数组
int len=strlen(y);
for (int i=1; i<=len; i++)
		cout<<nx[i]<<" ";

扩展kmp算法模版

const int maxn=1e6+5; 
int nx[maxn];
int extend[maxn];
 //nx[i]:			y[i...m-1] 与 y[0...m-1] 的最长公共前缀 
 //extend[i]:		x[i...n-1] 与 y[0...m-1] 的最长公共前缀 
void getnx_ex(char *x){
	int m=strlen(x);
	nx[0]=m;
	int j=0,k=1;
	while (j+1<m && x[j]==x[j+1]) j++;
	nx[1]=j;
	for (int i=2; i<m; i++){
		int p=nx[k]+k-1;
		int l=nx[i-k];
		if (i+l<p+1) nx[i]=l;
		else {
			j=max(0,p-i+1);
			while (i+j<m && x[i+j]==x[j]) j++;
			nx[i]=j;
			k=i;
		}
	}
}

void exkmp(char *x, char *y){
	getnx_ex(y);
	int n=strlen(x);
	int m=strlen(y);
	int j=0,k=0;
	while (j<m && j<n && x[j]==y[j]) j++;
	extend[0]=j;
	for (int i=1; i<n; i++){
		int p=extend[k]+k-1;
		int l=nx[i-k];
		if (i+l<p+1) extend[i]=l;
		else {
			j=max(0,p-i+1);
			while (i+j<n && j<m && x[i+j]==y[j]) j++;
			extend[i]=j;
			k=i;
		}
	}
}

//输出nx数组
int len=strlen(y);
for (int i=0; i<len; i++)
		cout<<nx[i]<<" ";

KMP循环节问题

HDU 3746
如果一个字符串为循环串时,(例如adcabcabc)那么它的next[]数组满足下面性质:
1、len%(len-nx[len])==0;
2、len/(len-nx[len])就是循环的次数

#include <bits/stdc++.h>
using namespace std;

const int maxn=1e5+5;
int nx[maxn];
void getnx(char *x) {
	int i,j;
	int m=strlen(x);
	j=nx[0]=-1;
	i=0;
	while (i<m) {
		while ( -1!=j && x[i]!=x[j]) j=nx[j];
		nx[++i]=++j;
	}
}

char s[maxn];
int main(){
	
	ios::sync_with_stdio(0);
	cin.tie(0);
	int T;
	cin>>T;
	while (T--){
		memset(nx,0,sizeof(nx));
		cin>>s;	
		getnx(s);
		int len=strlen(s);
		int same=len-nx[len]; //循环节的长度
		if (nx[len]==0) cout<<len<<endl;
		else if (len%same==0) cout<<0<<endl; 
		else cout<<same-len%same<<endl;
	}
	return 0;
} 
发布了18 篇原创文章 · 获赞 5 · 访问量 1166

猜你喜欢

转载自blog.csdn.net/qq_43640009/article/details/100419020