Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

KMP 算法是 D.E.Knuth、J,H,Morris 和 V.R.Pratt 三位神人共同提出的,称之为 Knuth-Morria-Pratt 算法,简称 KMP 算法。

问题:求 a 字符串与 b 字符串中子串相同的串首位置。

暴力就不说了,设 a 长 \(m\),b 长 \(n\),每次枚举比对每个字符,复杂度 \(O(nm)\)

KMP 主要思想:如果一个字符串的子串与前缀相等,那么在查找时就可以直接将前缀跳至该子串的位置。复杂度 \(O(n)\)

nxt[x] 记录x位置字符在查询串中的跳转位置。

eg:对于串abaabacac:

a b a a b a c a c

-1 0 0 1 1 2 3 0 1

1
2
3
4
5
6
7
8
9
10
inline void getnxt()
{
int j=0,k=-1;
nxt[0]=-1;
while(j<s.length()-1)
{
if(k==-1||s[j]==s[k])nxt[++j]=++k;
else k=nxt[k];
}
}

查询时跳转即可。

模拟一下就知道啦~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
string s,t;
int nxt[1000];
inline void getnxt()
{
int j=0,k=-1;
nxt[0]=-1;
while(j<s.length()-1)
{
if(k==-1||s[j]==s[k])nxt[++j]=++k;
else k=nxt[k];
}
}
inline int indexkmp()
{
int i=0,j=0;
while(i<s.length() and j<t.length())//如果比完了就退出来了
if(i==-1 or s[i]==t[j])i++,j++;
else i=nxt[i];
if(i>=s.length())return j-s.length();
return -1;
}
int main()
{
std::ios::sync_with_stdio(false);
cin>>s>>t;
getnxt();
cout<<indexkmp()+1;
return 0;
}

例题

洛谷P3375

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
const int maxn=1e6+5;
int nxt[maxn];
char a[maxn],b[maxn];
int lena,lenb;
inline void getnxt()
{
int k=-1,j=0;
nxt[0]=-1;
while(j<lena)
if(k==-1 or a[k]==a[j])
nxt[++j]=++k;
else k=nxt[k];
}
inline void indexkmp()
{
int j=0,i=0;
while(j<lena and i<lenb)
if(j==-1 or a[j]==b[i]){
i++,j++;
if(j==lena){
printf("%d\n",i-lena+1);
j=nxt[j];
}
}
else j=nxt[j];
}
int main()
{
scanf("%s\n%s",&b,&a);
lena=strlen(a);
lenb=strlen(b);
getnxt();
indexkmp();
for(int i=1;i<=lena;i++)
printf("%d ",nxt[i]);
return 0;
}

给小狼留言