前言
我将KMP算法的详解分为三个篇章:
【原理篇】:主要讲解KMP实现的原理,以及手动求NEXT数组。
->【数理篇】:主要讲解如何在手动求出NEXT数组的情况下,找出数学规律,为之后的算法实现奠定基础。
【实现篇】:主要讲解以C语言代码的方式实现KMP算法,以及NEXT数组的优化。
其余篇章将在之后更新
🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈
制作不易,若对你有帮助的话点赞、关注、评论走一波,你们的支持是我前进路上最大的动力。
前情提要:
在原理篇当中我已经讲解了KMP中最核心的NEXT数组,以及他的求法:NEXT[j]存储了从PAT[0]到PAT[j-1]位置,以PAT[0]为首,PAT[j-1]为结尾的两个最长子字符串的长度位(可以重叠,但不能相等)。忘记的朋友们可以看看之前的篇章。
数理篇正式开始:
0 |
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | |
PAT字符串 | a | b | c | a | b | a | b | c | a | b | c |
NEXT数组 | -1 | 0 | 0 | 0 | 1 | 2 | 1 | 2 | 3 | 4 | 5 |
现在有这样一个NEXT数组,除了NEXT[0]与NEXT[1]是已经规定好的-1和0之外,其余的都要我们手动去求。在上一个篇章当中,我们学会了如何用手去求NEXT数组。但在实际生产过程当中,这种方法肯定是不可取的,那么NEXT数组的构成当中有什么规律呢?
我们先假设在NEXT数组当中,有两个指针,一个叫i一个叫k。
设有NEXT[i]=k,也就是可以通过NEXT数组的下标去访问K指针所在的位置,这一假设是以下的推论的大前提。
此时就有p[0]--p[k-1](以首元素为头的子字符串)=p[x]--p[i-1](以i-1为尾的子字符串)这两个字符串相同,疑惑为什么相同的朋友们可以去看看NEXT数组的定义。那这里的X从哪里来的呢?
x是为了之后的推导,先假设出来的,如果不解继续往下看~
因为两字符串长度相同(定义),所以就存在关系 k-1-0=i-1-x,也就可以推导出x=i-k
此时再将x放回上文的推导关系,就有这样的一个关系p[0]--p[k-1]=p[i-k]--p[i-1]
情况1:PAT[i]=PAT[K]
当PAT[i]=PAT[K]时,也就是对应的两个字符相同,可以参考上图中i k对应的位置。又因为
p[0]--p[k-1]=p[i-k]--p[i-1],p[i]=p[k](字符相同),所以就有p[0]--p[k]=p[i-k]--p[i],
又因为从next[i]=k可以推导出p[0]--p[k-1]=p[i-k]--p[i-1],那么是不是p[0]--p[k]=p[i-k]--p[i]可以反向推导出next[i+1]=k+1!
那么也就可以得出情况一的结论:
在PAT[i]=PAT[k]的情况下,NEXT[i+1]=k+1。
那如果PAT[i]!=PAT[k]呢?那这就是我们的情况2
情况2:PAT[i]!=PAT[K]
那就非常简单粗暴了,k=NEXT[k],也就是一直往回退直到满足PAT[i]=PAT[k]这一情况时,在继续套用情况一进行推导。如图,此时PAT[i]!=PAT[K],那么,就令k=NEXT[k],也就是移动到,p[0]的位置,此时满足情况1PAT[i]=PAT[K],所以此时的NEXT[i+1]=k+1,也就是NEXT[4]=1。
若退回到0位置时还不相等呢?那继续往下退到-1岂不是越界了?这里可以加一个判定,若退到0还不满足,可以直接令NEXT[i+1]=0(-1+1),具体实现可以关注我下一篇KMP代码实现的讲解。
至此,本篇博客的内容九分钟带你弄懂KMP算法【数理篇】告一段落,若对你有些许帮助,可以点赞、关注、评论支持下博主,你的支持将是我前进路上最大的动力。
若以上内容有任何问题,欢迎在评论区指出。若对以上内容有任何不解,都可私信评论询问。
诸君,山顶见!
🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈