KMP(快速查找匹配串的算法)
问题解决:判断B是否A的子串,并找到字符串B中在字符串A中的位置。
时间复杂度 :O(N+M), N,M分别是字符串A和B的长度。
核心点:对于字符串B,数组next[i]
表示B中以i结尾的非前缀子串与B的前缀能够匹配的最长长度。也就是前缀B[1]...B[next[i]]
和B[i-next[i]+1]....B[i]
相等,很明显B[i]==B[next[i]]
,有了next数组之后,我们就可以对A,B字符串进行匹配了。
匹配流程:
- 设i,j分别是指向A和B的下标,此时
A[i-j]...A[i-1] == B[1]...B[j]
,也就是说B的前j的字符已经匹配成功了。 - 如果
A[i]==B[j+1]
,i++,j++。 - 如果
A[i]!=B[j+1]
,j=next[j],直到j==0
或者A[i]==B[j+1]
, 为什么这样做?那是因为B[1]...B[next[j]] == B[j-next[j]+1]...B[j]
,所以B[1]...B[next[j]] == A[i-next[j]]...A[i-1]
,这样我们就只需要继续匹配A[i]和B[j+1]而不需要回溯i。
核心代码:
for(int i=2,j=0;i<=m;i++)
{
while(j&&p[i]!=p[j+1]) j=ne[j];
if(p[i]==p[j+1]) j++;
ne[i]=j;
}
for(int i=1,j=0;i<=n;i++)
{
while(j&&s[i]!=p[j+1]) j=ne[j];
if(s[i]==p[j+1]) j++;
if(j==m)
{
//匹配成功
}
}
如何求B数组的next数组呢?
其实流程是一样的,就是B和B自己的一个匹配。
- 假设两个相同的字符串B1和B2,此时匹配的下标是i和j,并且
next[1~i-1]
已经算出来了。 - 不断地扩展j直到
B1[j] == B2[i]
此时next[i] == j
。