KMP算法是一种高效的字符串匹配算法。
KMP算法的特点是给定一个主串,给定一个匹配串,问匹配串在主串中出现的次数,匹配串在主串中出现的位置等。
首先我们先看一种暴力的方法——按位对比,若匹配失败从头再来。
我们用两个指针,一个指针i指在主串,一个指针j指在匹配串,
如果s1[i+1]!=s2[j+1],根据暴力的思想就从头开始匹配,i=匹配开头+1,j=1;
显然这么不优,这样太过暴力,KMP算法的核心思想就是对于匹配失败后j的位置做一个优化。
我们来看下面这种情况
s1='aabaac' s2='aabaabaac'
当i=j=5的时候 显然s[i+1]!=s[j+1];
若是按照原来暴力的想法此时应把匹配串的j调整为1,i调整为匹配开头+1;
但我们发现匹配串有个性质就是部分回文,s1的前五个元素为aabaa,此时如果把i++,j=3便可继续匹配。
利用这个性质,我们可以对原方法有一个很大的优化即——KMP算法。
KMP的核心是预处理一个fail数组即确定匹配失败后,j指针应该调整到哪个位置。
预处理的方法就是自我匹配,显然fail[1]=0;
1 int s2_len=strlen(s2+1); 2 int j=1; 3 for(int i=1;i<=s2_len;i++) 4 { 5 while(s[i]!=s[j+1]&&j>0) j=fail[j]; 6 if(s[i]==s[j+1]) j++; 7 fail[i]=j; 8 }
然后匹配匹配串与主串即可。
全部代码洛谷P3375
1 #include<cstdio> 2 #include<iostream> 3 #include<cstring> 4 #include<algorithm> 5 6 using namespace std; 7 8 int kmp[1000005],n,m; 9 char s1[1000005],s2[1000005]; 10 11 int main() 12 { 13 scanf("%s%s",s1+1,s2+1); 14 n=strlen(s1+1); 15 m=strlen(s2+1); 16 kmp[1]=0; 17 int j=0; 18 for(int i=2;i<=m;i++) 19 { 20 while(j&&s2[j+1]!=s2[i]) j=kmp[j]; 21 if(s2[j+1]==s2[i]) j++; 22 kmp[i]=j; 23 } 24 j=0; 25 for(int i=1;i<=n;i++) 26 { 27 while(j&&s1[i]!=s2[j+1]) j=kmp[j]; 28 if(s2[j+1]==s1[i]) j++; 29 if(j==m) 30 { 31 printf("%d ",i-m+1); 32 j=kmp[j]; 33 } 34 } 35 for(int i=1;i<=m;i++) 36 printf("%d ",kmp[i]); 37 return 0; 38 }