文章目录
KMP算法
分析Brute-Force算法的缺点(简称暴力算法)
先举个例子,看看暴力算法的执行过程
该算法的缺点从第五步开始显示出来,分析如下
第五步进行了指针回退,重新开始模式串和目标串的比较,这有什么不好呢?实际上,第五步中目标串的第二个字符在第二步已经与a比较过。
重复比较如下图所示
这是暴力算法的缺点,进行多次重复的比较
有没有什么办法可以跳过多次重复比较呢?
KMP算法的思想
我们尝试去跳步
举一个暴力算法失败匹配的例子,如下图所示
o和a不匹配,前面的字符hell比对成功。这意味着hell两个串是一模一样的,我们能不能这样想,既然都一样了,然后o和a又比较失败了。我们能不能直接跳过hell的匹配(因为已经比对过了),直接就从失败匹配的下一个地方开始?
如下图
回到第一个例子,刚才的跳步有个问题
是不是发现跳太多了?多在哪里?那我们跳步应该跳到什么地方比较合适?再举个例子给你。
OK,观察上面的例子,我们发现,我们只要把失配位置前面的部分分析分析,就能发现,只要把模式串的头头和目标串的屁屁一样的地方对上,就是合适的。
诶?所以问题就归结成,找模式串的最大相等前后缀,为什么要最大呢?因为想尽可能跳步。
最大相等前后缀
next数组概念介绍
以上一个例子求最大相等前后缀,假设我们在j处发生失配,则有最大相等前后缀next[j]
此处,next[4]=2,这代表这在坐标4之前,最大相等前后缀为2。
仔细分析发现,最大相等前后缀跟目标串没关系,跟模式串最大相等前后缀有关系。
next数组求解例子
再举一个例子aaab,求在不同位置失配的next数组
在0处就失配,意思就是第一个就失配,那都不用讨论前后缀了,指针直接指向下一处。我们令这种情况为-1,方便算法的实现
在1处失配,最小相等前后缀为0,没有。我们把这种情况列为其他情况,
在2处失配,最小相等前后缀为1,
这里需要注意啊,最小相等前后缀的后缀不能从0开始,不然上下是不是就一样了,还能跳步吗?
在3处失配,最小相等前后缀为2
我们可以整理成下表
next数组公式如下
算法实现如下
求next数组算法
//基本思路就是从最大的可能的前后缀开始,慢慢缩小范围
void GetNext(SqString t,int next[])//有模式串t求出next数组
{
int j=0,k=-1;
next[0]=-1;
while(j<t.length-1)
{
if(k==-1 || t.data[j]==t.data[k])
{
j++;k++;
}
else k=next[k];
}
}
KMP算法实现
int KMPIndex(SqString s,SqString t)
{
int next[MaxSize],i=0,j=0;
GetNext(t,next);
while(i<s.length&&j<t.length)
{
if(j==-1||s.data[i]==t.data[j])
{
i++;
j++;
}
else
j=next[j];
if(j>=t.length)
return(i-t.length);
else
return(-1);
}
}