推荐blog:
https://www.luogu.com.cn/blog/pks-LOVING/zi-fu-chuan-xue-xi-bi-ji-qian-xi-kmp-xuan-xue-di-dan-mu-shi-chuan-pi-post
http://www.matrix67.com/blog/archives/115(先看这些blog)
首先,普通字符串匹配是一个一个进行匹配,配不上了,就将整个字符串往后挪一位,再从头开始匹配,大概就像这样:
但这样的时间复杂度为O(nm);
而KMP这不一样,下面我来演示以下:
大概是这样的两个串
接下来进行匹配
比如粉色代表匹配成功,但在下一位匹配时却匹配失败了,按照普通的搞法,应该是将b往后挪一位,咱们从头再来,但kMP却是这样的:
我们发现标蓝的部分相同(当前匹配位置的后缀与前缀相同的最长部分),那么,我们可以直接将b蓝色的前一部分,挪到后一部分蓝色,就像这样
然后继续往后进行匹配,反复这些操作,直至找到一次完全匹配,然后再继续匹配
如何迅速找到当前位置border的最大长度呢(注:border就是一个串前缀和后缀相等部分的最大长度)
可以自己先跟自己匹配,用一个数组next[i]来表示位置i的boder的长度
自己怎么跟自己匹配?自己跟自己不是一样的吗?(迷惑)
没有关系,既然知道自己跟自己匹配时从第一位开始匹配是一样的,那用自己的第二位与自己的第一位开始匹配就可以了
推荐题:洛谷P3375
代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int kmp[1000006]; 4 char a[1000006],b[1000006]; 5 int main(){ 6 int lena,lenb,i,j; 7 cin>>a+1>>b+1; 8 lena=strlen(a+1);lenb=strlen(b+1); 9 j=0; 10 for(i=2;i<=lenb;i++){ 11 while(j&&b[j+1]!=b[i])j=kmp[j]; 12 if(b[j+1]==b[i])j++; 13 kmp[i]=j; 14 }j=0; 15 for(i=1;i<=lena;i++){ 16 while(j&&b[j+1]!=a[i])j=kmp[j]; 17 if(b[j+1]==a[i])j++; 18 if(j==lenb){ 19 cout<<i-lenb+1<<endl; 20 j=kmp[j]; 21 } 22 } 23 for(i=1;i<=lenb;i++)cout<<kmp[i]<<" "; 24 return 0; 25 }