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数组的主要内容,如果未能解决你的问题,请参考以下文章