KMP算法——详解next数组

Posted Aline2021-yxz

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了KMP算法——详解next数组相关的知识,希望对你有一定的参考价值。

令人烦恼的next数组,本文是作者自己的理解与思考,并不完善,只是为了提示自己,如果您已研究了KMP算法,本文对您的帮助并不大


next数组完成的任务:

当s1与s2字符串比较到上图所示位置时,拥有next数组的KMP算法不需要像BF算法一样:

  • 将 j 回退到开始的第二个字符
  • 将 i 退回到字符串头部

而是:

  • 将 i 回退到第二个字符b处
  • j 不动

因为图示位置的前面都是匹配的字符 , 相匹配的字符串一定具有相同的前缀,所以b,c的比较就显得有点浪费资源,所以只需要找到相同的前缀就可以减少比较次数,而帮助我们实现这种功能的就是:
KMP的精髓——“next数组

next数组的创建:

前面说了,我们只需要找相同的前缀就可以确定i指针回退的位置,例如:
子串为: a b c a e
那么假设在a位置匹配失败,那么就必须从头开始重新匹配
假设在b位置匹配失败,那么也必须从头开始
假设在c位置匹配失败,同理,从头开始
假设在a位置匹配失败,同理,从头开始
假设在e位置匹配失败,因为前一个字符为a,与子串开始的a相同,那么就没必要从头开始,只需从b开始

那么其所对于的next数组为:
-1 0 0 0 1
你可以多举几个例子观察,不难得出:

❗❗❗注意: 头位置与头位置的下一个位置的next数组对应值应该都为0,但是为了方便,一般将头位置的next数组值设置为-1。

💡匹配失败位置next数组值=前缀子串后缀子串最大相同子串长度

如果不存在后缀子串,那就是匹配失败位置的next数组值就是0

前缀子串:从头开始,以匹配失败位置的前一个字符结束(不是到不匹配位置的前一个)

后缀子串:不从头开始,以与头相同的字符开始到匹配失败位置之前结束

因为所有的前缀与后缀字符串中相同的两个的长度为2,那么对于e的next值就是2

感觉总结的不是很精辟,恕博主表达不是很好。

上面对next数组的创建都是人该怎么做,但是对于机器来说,他又不能和我们一样肉眼观察,我们该怎么算next值呢?

我们随便拿一个例子:

经过观察得到了以下结论:

  • 以当前位置的next值为下标的字符是前缀字符串的下一个字符,当前位置的字符是后缀字符串的下一个字符;
  • 以当前位置的next值作为下标,如果下标处的字符和当前位置的字符相等,那么下一个位置的next值就是作为下标的next值+1;
  • 以当前位置的next值作为下标,如果和当前位置的字符不相等,就将作为下标的next值对应的next值再作为下标重复操作;

3处的next值为1,那么下标为1处的字符b就是前缀字符串的下一个字符,3处的字符为b,是后缀字符串的下一个字符,因为前缀字符和后缀字符相同,并且前缀字符的下一个与后缀字符串的下一个相同,那么4位置的next值就是2

前面两个结论是很好理解的,最难理解的就是最后一个,在看个例子:

要求6位置处的next值,我们按照上面的结论走:
1:以下标为5的next值也就是2为下标,找到前缀字符串的下一个字符‘c’,下标为5处的字符为后缀字符串的下一个字符;
2:两者不相等,以2下标的next值为下标,作为前缀字符串的下一个字符,即为0下标处的‘a’,后缀字符串的下一个字符仍然为a;
3:两者相同,那么当前位置的下一个位置的next值为0+1=1;

对于不相同时为什么是这样做,来自其他博文的介绍:

但博主仍不是很理解为什么一到B那么就必然是相同的,为什么就可以确定后缀字符串中第一个一定是A,有明白的小伙伴可以再评论区解答哦。

以上是关于KMP算法——详解next数组的主要内容,如果未能解决你的问题,请参考以下文章

KMP算法——详解next数组

KMP算法——详解next数组

KMP算法——详解next数组

KMP算法的Next数组详解

关于KMP算法中,获取next数组算法的理解

KMP的next数组求法详解