kmp算法nexts数组通俗化解释

最近研究了一下kmp算法,确实很绕人,弄了两天终于弄懂了
这里想要采用通俗化的语言解释一下,文章不长,希望大家能够耐心读完。
nexts数组主要记录前后缀相同的数量,比如
aba前后缀都有a,所以下一位为1。
nexts数组找前后缀问题比较简单,其他大佬的博客都已经详细论述了,我这菜鸡就不在这丢人现眼了

int  i=0,j=-1;
nexts[0] = -1;
while(i < m)
{
    if(j == -1||data[i] == data[j])
    {
        i++;
        j++;
        nexts[i] = j;
    }
    else
    {
        j = nexts[j];
    }
}

首先nexts数组保存的是前一位的相同值,nexts[0]固定为-1,便于在nexts数组查到头之后i++,j++为下一位赋值为0,此时的情况是无前后缀相同。
接下来是匹配失败的过程,j = nexts[j]的情形
这里重点解释一下这个问题,也是nexts数组的核心问题
首先我将j = nexts[j]分为两类,第一类是j = nexts[j]最终回到0的情况,第二类是j = nexts[j]最终回到不为0的情况
先看第一种情况
项数 : 0 1 2 3 4 5
数组 : 1 2 3 1 3 6
nexts:-1 0 0 0 1 0
这里重点观察nexts[5]的值
由于nexts数组为找前面的最大前缀,所以i = 4,j = 1
(前面i =3,j = 0时匹配成功,nexts[4] = 1)
接着算法会接着前面的公共前缀1继续往下找,也就是比较1 2 3 1 3
中的下一位1 2与1 3是否相等,此时2与3匹配失败,j = nexts[j]
此时最终回到i = -1的位置,i++,j++,nexts[5] = 0;
这里j最终回到-1的根本原因是因为1 2这个数组没有公共的前缀!!!
再看第二种情况
项数 : 0 1 2 3 4 5 6 7
数组: 1 2 1 2 1 2 3 4
next: -1 0 0 1 2 3 4 0
这里重点观察nexts[7]的值,也就是重点探讨0~6之间的数据关系
即字符串1 2 1 2 1 2 3的前后缀
在前面的1 2 1 2 1 2数组之中,由于有共同前后缀1 2 1 2
所以此时i = 6,j = 4,重点比较1 2 1 2 1 2 3中的1 2 1 2 1与后缀1 2 1 2 3能否匹配上
前面的1 2 1 2已经比较过了,比较1与3后失配
此时j = nexts[j]的根本原因是前面的1 2 1 2有相同的前后缀1 2 1 2!!!
这里使用数学公式说明一下,设1 2 1 2 1中的前面1 2为a,后面1 2为b,1 2 1 2 3中的前面1 2为c,后面的1 2为d
已知1 2 1 2 = 1 2 1 2,前面可以匹配成功,所以a = c,b = d
又因为通过nexts数组可以看出前面1 2 1 2的前后缀,发现a = b
所以有a = d,此时虽然1 2 1 2 1与1 2 1 2 3失配了,但是1 2 1的1 2与1 2 3的1 2仍然能够匹配上!!
所以找到前面的nexts后再对1 2 1中的1与1 2 3中的3比较依次

总结:通过nexts数组的分析可以看出,其实算nexts数组可以看作是一个递归的问题,原字符串失配后再通过原字符串之前的匹配进行继续比较,只是这种形式通过数组记录了前面的前后缀,与常规的递归方式不同,它的递归是采用数组往前寻找的形式实现的。

发布了30 篇原创文章 · 获赞 9 · 访问量 3566

猜你喜欢

转载自blog.csdn.net/znevegiveup1/article/details/104550652