KMP算法

简化:

​ 第一步简化,找寻主串S中和模式串P第一个字母相同的字母,这个需要遍历主串,无法优化,在比较的时候寻找就行。

​ 第二部优化,保持主串位置不动,优化模式串移动的位置,朴素匹配法移动一个位置。但在前一轮的比较中,我们已经知道了P的前(j-1)位与S中间对应的(i-1)个元素已经匹配成功了。这就意味着,在一轮的尝试匹配中,我们get到了主串的部分内容,我们能否利用这些内容,让P多移几位(MP算法优化点),减少遍历的趟数呢?答案是肯定的。

​ 分析可知(具体可参考文章底部博文链接),每次失配,S串的索引i不动,P串的索引j定位到某个数。时间效率明显提高。而这“定位到某个数”,这个数就是接下来引入的next值。

难点在求next()值这。

next():

公式如下

image.png

推理:

有公式可知,next值的重点就是求p1...pk--1=pj-k+1...pj-1时k的最大值,即模式串首(p1...pk--1)尾(pj-k+1...pj-1)重合部分的最大值。

有定义可知

j=1

​ next[1] = 0;

没有任何匹配的情况下

​ next[j] = 1;

首尾重合的时候:

当j+1时,它的最大首尾重合部分有可能为

当p1...pj--1=p2...pj => next[j] = j

当p1...pj--2=p3...pj-1 => next[j] = j-1

当p1...pj--3=p4...pj-1 => next[j] = j-2

。。。

当p1pj2=pj-1...pj => next[j] = 3

当p1=pj-1=> next[j] = 2

当p1!=pj-1=> next[j] = 1

如果我们已经知道 next[j] = k,即 p1...pk-1 = pj-k+1...pj-1 时,此时 next[j+1]是多少呢?有两种情况:

当pk=pj,即:p1...pk = pj-k+1...pj,(11...pk-=pj-k+1...pj成立。此时为next[j+1] = k+1。(代码第四行)。

这里加一句话:读到这里时我有个疑问,当pk=pj,如果主串的Si!=pj,那么Si!=pk,那么此时next[j+1] = k+1就不成立了,后来一想,如果Si!=pj,那也就不会去比较Si+1!=pj+1,也就和next[j+1]没什么关系了。

当pk!=pj,即:p1...pk != pj-k+1...pj,我们需要在pj-k+1...pj中找寻一个子串,假设长度为k',使p1...pk‘ = pj-k’+1...pj成立,也就是在p1...pk中存在一个子串,使p1...pk‘ = pk-k’+1...pk,这个等式换个角度一看,把k’当k,k当j,你会发现,这个其实就是求j = k的next值,因为k

又上述过程得出传说中的5行代码:

void getNext(char[] chars,int len,int[] next){
    next[1] = 0; int i=1,j=0;
    while(i

参考博文:

https://blog.csdn.net/qq_37969433/article/details/82947411

《数据结构(c语言版)》,严蔚敏老师版。

你可能感兴趣的:(KMP算法)