KMP算法next数组生成中k=next[k]解释

本文适用于读者对KMP算法有一定的了解

void initNextArray(string p){
    int k = -1;
    int j = 0;
    next[0] = -1;
    while(j < p.size()-1){
        if(k == -1 || p[k] == p[j])
            next[++j] = ++k;
        else
            k = next[k];
    }
}

上述代码是KMP算法中next数组的创建过程,最难理解的过程就是k = next[k];这一行代码,今天给大家来解释一下这句代码背后隐藏的递归思想。
首先给大家捋一捋各个参数的意义
j是模式串的当前角标
k是在模式串当前角标之前已经匹配的前缀后缀的长度。
next[j]表示在角标j之前已经匹配的前缀后缀的长度。

算法思想:利用当前已知的next[j]和k并结合p模式串特点推算出next[j+1]

已知的next[j]和k意味着前提为p[0]p[2]…p[k-1] == p[j-k]p[j-k+1]…p[j-1]
推算next[j+1]则要使用字符p[j]与字符p[k]作比较。

如果p[k] == p[j];
则可得 p[0]p[2]…p[k-1]p[k] == p[j-k]p[j-k+1]…p[j-1]p[j];
即执行next[++j] = ++k; 已经匹配的前后缀长度k加1之后赋给角标为j+1的next数组的元素。注意此时j这个游标后移了一位,意味着可以进行下一个next元素的求解。

如果 p[k] != p[j]
那么该怎么办?为什么k = next[k]?
既然找不到最大匹配前后缀长度,我们就应该退而求其次,找到一个相对较短的匹配前后缀,而且这个next[j+1]的值是不固定的
提供下面简单的三种情况:
《KMP算法next数组生成中k=next[k]解释》

《KMP算法next数组生成中k=next[k]解释》

《KMP算法next数组生成中k=next[k]解释》
上述标红内容就是在不匹配发生时,next[j+1]的取值各不相同,而k = next[k]可以很好的识别出来;
前提是已知next[j]和k的值,求next[j+1]的值
有前提可知 p[0]p[2]…p[k-1] == p[j-k]p[j-k+1]…p[j-1]
但是p[k] != p[j],那我们就应该找稍微短一些的匹配前后缀串
next[k]的意义是在模式串的k角标之前的匹配的前后缀串的长度
也就是存在一个k’,使得p[0]p[1]…p[k’-1] == p[k-k’]p[k-k’+1]…p[k-1]
结合前提推得 p[0]…p[k’-1] == p[j-k’]p[j-k’-1]…p[j-1];
详细分析可以结合图片理解:
《KMP算法next数组生成中k=next[k]解释》
上图最后一部分的红色部分即为更短的匹配前缀后缀,k = next[k]这句话的意义就可以明白了,注意这时候j并没有向后移动,也就意味着下一次循环中p[j]和p[k’]需要继续进行比较,如果还是不相等,那么就要继续k = next[k];(即k = next[next[k’]])递归就体现在这里,如果一直不相等,最后的k会变为-1,那么这个时候”递归”就结束了,执行next[++j] = ++k(k有初始化为0,next[j+1]也被赋值为0,并且j游标也后移了一位,可以继续初始化next数组了)。
next数组在此基础上还可以进行优化,网上资料挺多,就不赘述了。

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/BaiDingLT/article/details/69808221
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞