若不经常出现子串与模式串部分匹配的问题,KMP算法和朴素算法差不多
KMP算法:主串不回溯,只有模式串的指针回溯
求next数组
当模式串的第 j 个字符匹配失败时,令模式串跳到 next[j],再继续匹配
串的前缀:包含第一个字符且不包括最后一个字符的子串
串的后缀:包含最后一个字符且不包括第一个字符的子串
当第j个字符串匹配失败,由前1~j-1个字符组成的串记为S,则:
next[j] = S的最长相等前后缀长度+1
注:next[1] = 0
模式串:ababaa
序号J | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 |
模式串:aaaab
序号J | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
模式串 | a | a | a | a | b |
next[j] | 0 | 1 | 2 | 3 | 4 |
KMP算法实现
//S为原串,T为模式串,next是构造的数组
int Index_KMP(SString S,SString T,int next[])
{
int i=1,j=1;
while(i<=S.length && j<=T.length)
{
if(j==0 || S.ch[i]==T.ch[i])
{
++i;
++j;
}
else
j = next[j];
}
if(j>T.length)
return i-T.length;
else
return 0;
}
//next[]不作为参数传进来
//平均时间复杂度O(m+n)
int Index_KMP(SString S,SString T)
{
int i=1,j=1;
int next[T.length+1];
get_next(T,next);//时间复杂度O(m),m为模式串长度
while(i<=S.length && j<=T.length)
{
if(j==0 || S.ch[i]==T.ch[j])
{
++i;
++j;
}
else
j=next[j];
}
if(j>T.length)
return i-T.length;
else
return 0;
}
优化next数组——>nextval
解决无意义对比
模式串:google
序号 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
模式串 | g | o | o | g | l | e |
next[j] | 0 | 1 | 1 | 1 | 2 | 1 |
nextval[j] | 0 | 1 | 1 | 0 | 2 | 1 |
模式串:aaaab
序号 | 1 | 2 | 3 | 4 | 5 |
---|---|---|---|---|---|
模式串 | a | a | a | a | b |
next[j] | 0 | 1 | 2 | 3 | 4 |
nextval[j] | 0 | 0 | 0 | 0 | 4 |
模式串:ababaa
序号 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
模式串 | a | b | a | b | a | a |
next[j] | 0 | 1 | 1 | 2 | 3 | 4 |
nextval[j] | 0 | 1 | 0 | 1 | 0 | 4 |