kmp算法总结

kmp算法总结

kmp算法可以以 \(O(n+m)\) 的超低复杂度来实现两个字符串的匹配功能。

我们先来定义一下 \(kmp_i\) 的意思是从 \(i\) 开始如果不能匹配的话,要跳会到哪里。

举个例子:

abcabdabcc
0001201230
abcabcabc
000123456

这个kmp有一个性质就是 \(kmp_i\) 表示 ss[1~i] 的前缀和后缀相等的情况下的最长长度。

然后我们在匹配是如果有失衡(也就是不匹配)的话,直接根据kmp往后跳就行。

很多情况下,不用跳到开头就可以接下去,所以可以大幅减小复杂度。

首先先预处理一下:

for(int i=2;i<=len2;i++){
	while(j&&ss[i]!=ss[j+1]){//此处判断j是否为0的原因在于,
		j=kmp[j];//如果失配 ,那么就不断向回跳,直到可以继续匹配 
	}
	if(ss[j+1]==ss[i]){
		j++;///果匹配成功,那么对应的模式串位置++ 
	}
	kmp[i]=j;
}

然后再做:

for(int i=1;i<=len1;i++){//如果失配 ,那么就不断向回跳,直到可以继续匹配 
	while(j&&s[i]!=ss[j+1]){
		j=kmp[j];
	}
	if(s[i]==ss[j+1]){
		j++;
	}
	if(j==len2){
		cout<<i-len2+1<<endl;
		j=kmp[j];
	}
}

code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
string s,ss;
ll len1,len2,kmp[2000000],j;
int main(){
	cin>>s>>ss;
	len1=s.size();
	len2=ss.size();
	s=' '+s;
	ss=' '+ss;
	for(int i=2;i<=len2;i++){
		while(j&&ss[i]!=ss[j+1]){
			j=kmp[j];
		}
		if(ss[j+1]==ss[i]){
			j++;
		}
		kmp[i]=j;
	}
	j=0;
	for(int i=1;i<=len1;i++){
		while(j&&s[i]!=ss[j+1]){
			j=kmp[j];
		}
		if(s[i]==ss[j+1]){
			j++;
		}
		if(j==len2){
			cout<<i-len2+1<<endl;
			j=kmp[j];
		}
	}
	for(int i=1;i<=len2;i++){
		cout<<kmp[i]<<" ";
	} 
}
posted @ 2025-06-06 10:29  MistyPost  阅读(9)  评论(0)    收藏  举报