KMP学习笔记
功能
字符串T,长度为n。
模板串P,长度为m。在字符串T中找到匹配点i,使得从i开始T[i]=P[0], T[i+1]=P[1], . . . , T[i+m-1]=P[m-1]
KMP算法先用O(m)的复杂度对模板串进行处理,然后O(n)进行匹配。总时间复杂度O(m+n)
注意失配函数f[i]为第i位处不能匹配时应当转向检查第f[i]位是否匹配:
比如模板串:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
A |
B |
B |
A |
A |
B |
A |
得到的失配函数为:
0 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
0 |
0 |
0 |
0 |
1 |
1 |
2 |
1 |
也即是说如果在模板串第5位失配,即当前位匹配不成功:
字符串 |
X |
X |
A |
B |
B |
A |
A |
K |
X |
模板串 |
|
|
A |
B |
B |
A |
A |
失配 |
|
那么根据失配函数f[5]=1,转移到1,表示已经匹配好一位,相当于模板串整体右移,但当前匹配的位置不变,然后继续匹配。
字符串 |
X |
X |
A |
B |
B |
A |
A |
K |
X |
模板串 |
|
|
|
|
|
|
A |
… |
|
失配函数另一种用途:如果P存在循环节,f[i]为前一个循环节对应字符的位置。比如ABCABC,那么P[4]=B,而f[5]=2,也就是P[1]=B。
用途:计算字符串循环节长度。
构造失配函数:
s为模板串,f为待构造的失配数组,开始时为空
void getFail(char *s,int *f) { int m=strlen(s),j; f[0]=0;f[1]=0; for (int i=1;i<m;i++) { j=f[i]; while (j&&s[i]!=s[j]) j=f[j]; f[i+1]=(s[i]==s[j]?j+1:0); } }
匹配函数:
输入
t:文本,一大串字符串
s:模板,待匹配的模板
f:失配数组,一开始为空,函数过程中调用失配数组构造函数
输出
t字符串中模板第一次出现的位置(从0开始)
int find(char *t,char *s,int *f) { int n=strlen(t),m=strlen(s); getFail(s,f); int j=0; for (int i=0;i<n;i++) { while (j&&s[j]!=t[i]) j=f[j]; if (s[j]==t[i]) j++; if (j==m) return i-m+1; } }