KMP算法
简介
在 的开始下标(从 开始):
可以在 的时间复杂度内将 与 匹配。
预处理
首先有一个定义:真前(后)缀是不包含原串的前(后)缀字串。
我们定义 为以第 个字符为结尾的字符串的真后缀与真前缀匹配的最大长度。
以下我们模拟对一个字符串求 :
- 。没有真前(后)缀。
- 。
- 。
- 。 与 匹配。
- 。 与 匹配。
- 。 与 匹配。
- 。
特别地,。
接下来介绍求法。
我们设 为处理到了 , 为前缀最大匹配到长度为 的子串,当前要匹配 。(因为字符串从 0 开始存储,所以 也是接下来要匹配的字符串)
开始时,。。
当 时(失配),此时的 就是不合法的,考虑移动 。如果暴力重新匹配,时间花费大。
此时要想起 为第 个字符为结尾匹配的最大长度,此时的 就表示以第 个字符结尾匹配的的最大长度。新的 肯定也要和 匹配。所以使 ,找到能匹配的最大长度。
当 时,。
匹配
只需要按照同样的步骤,当匹配的长度等于匹配串时,说明匹配成功。
Code
#include<bits/stdc++.h>
using namespace std;
int f[1000005];
void init(string &s) {
int len=s.size(),j=0;
f[0]=f[1]=f[2]=0;
for(int i=1;i<len;i++) {
while(j&&s[i]!=s[j]) j=f[j];
if(s[i]==s[j]) j++;
f[i+1]=j;//第 i 个字符
}
}
void kmp(string &s1,string &s2) {
int n=s1.size(),m=s2.size();
for(int i=0,j=0;i<n;i++) {
while(j&&s1[i]!=s2[j]) j=f[j];
if(s2[j]==s1[i]) j++;
if(j==m) {
cout<<i-m+2<<"\n";
j=f[j];
}
}
}
string s1,s2;
int main() {
cin>>s1>>s2;
init(s2);
kmp(s1,s2);
int l=s2.size();
for(int i=1;i<=l;i++) {
cout<<f[i]<<" ";
}
return 0;
}

浙公网安备 33010602011771号