KMP算法是一种性能比较好的字符串匹配算法。
首先,在理解性能比较好的KMP算法之前,我们首先要先想一下对于字符串匹配的朴素暴力做法我们一般是怎么做出来的。
举个例子:
对于主串s[n],子串p[m]。我们要计算子串p[m]在主串中出现的位置的话。核心代码一般是下面这个样子的:
for(int i=1;i<=n;i++)//关于主串
{
bool flag=true;//判断此时要匹配的两个字符是否相等,相等即为true;
int k=i;//k对i的值进行记录
for(int j=1;j<=m;j++)//关于子串
{
if(s[k]!=p[j])
{
flag=false;
break;//跳过本次循环,p从头开始与主串s的下一个字符进行比较
}
else
k++;
}
if(flag)//说明匹配成功
cout<<i<<endl;//输出字符串匹配开头的成功位置
}
这种做法的时间复杂度是O(mn)的。
这种做法最大的时间浪费体现在每一次匹配不成功,子串p都要从头开始与主串的下一个字符进行匹配。
如果我们能够对子串进行预处理,记录下子串每个位置后缀和前缀相等的最大长度,这样我们每次在第二重循环中对j开始处理时就可以直接从当前位置的长度开始,而不必每次都从1开始,我们把每个位置的这些长度值所组成的数组叫做next数组。
我们求next数组的核心代码如下:
for (int i = 2, j = 0;i <= m;i++)
{
//next[1]一般情况都是0,前缀和后缀相等的不能够是其本身
while (p[j + 1] != p[i] && j) j = next[j];//后缀不相等时j回到上一次与后缀相等的位置
if (p[j + 1] == p[i]) j++;//当后缀和前缀的字符相等时,j++,继续进行匹配
next[i] = j;
}