算法设计与分析——暴力算法关于KMP算法中next函数的详细解析
以下采用的next 数组是从1开始的 并且其他情况的赋值为1
借鉴了两篇优秀的文章作为算法设计分析蛮力法下的kmp知识补充
https://blog.csdn.net/qq_37457202/article/details/80446659
同感,之前看到数据结构中字符串的模式匹配时,花了半天的时间,才把KMP算法中的next函数整明白了,结果过了几天在看到这时,只记得next[j+1]=next[j]+1,可是有时候能套公式正确算出,有时候就算不对,所以今天再重新理一遍思路,顺便记录下来,防止哪天脑子再短路了,又不知道怎么求解的了。 先看看next数据值的求解方法
位序 1 2 3 4 5 6 7 8 9
模式串 a b a a b c a b c
next值 0 1 1 2 2 3 1 2 3
next数组的求解方法是:
1.第一位的next值为0
2.第二位的next值为1
后面求解每一位的next值时,根据前一位进行比较
3.第三位的next值:第二位的模式串为b ,对应的next值为1;将第二位的模式串b与第一位的模式串a进行比较,不相等;则第三位的next值为1(其他情况均为1)
4.第四位的next值:第三位的模式串为a ,对应的next值为1;将第三位的模式串a与第一位的模式串a进行比较,相同,则第四位的next值得为1+1=2
5.第五位的next值:第四位的模式串为a,对应的next值为2;将第四位的模式串a与第二位的模式串b进行比较,不相等;第二位的b对应的next值为1,则将第四位的模式串a与第一位的模式串a进行比较,相同,则第五位的next的值为1+1=2
6.第六位的next值:第五位的模式串为b,对应的next值为2;将第五位的模式串b与第二位的模式中b进行比较,相同,则第六位的next值为2+1=3
7.第七位的next值:第六位的模式串为c,对应的next值为3;将第六位的模式串c与第三位的模式串a进行比较,不相等;第三位的a对应的next值为1,
则将第六位的模式串c与第一位的模式串a进行比较,不相同,则第七位的next值为1(其他情况)
8.第八位的next值:第七位的模式串为a,对应的next值为1;将第七位的模式串a与第一位的模式串a进行比较,相同,则第八位的next值为1+1=2
9.第八位的next值:第八位的模式串为b,对应的next值为2;将第八位的模式串b与第二位的模式串b进行比较,相同,则第九位的next值为2+1=3
如果位数更多,依次类推
KMP算法的关键在于求算next[]数组的值,即求算模式串每个位置处的最长后缀与前缀相同的长度,下面按照递推的思想总结一下求解next[]数组:
根据定义next[1]=0,假设next[j]=k, 即P[1...k-1]==P[j-k,j-1]
1)若P[j]==P[k],则有P[1..k]==P[j-k,j],很显然,如果next[j]=k; 则next[j+1]=next[j]+1=k+1;否则next[j+1]=k+1!=next[j]+1;(当初就想着记公式简单可以直接套用呢,结果只记住next[j+1]=next[j]+1以至于后来迷糊了)2)若P[j]!=P[k],则可以把其看做模式匹配的问题,即匹配失败的时候,k值如何移动,显然k=next[k]。
因此可以这样去实现:
void getNext(char *p,int *next)
{
int j,k;
next[1]=0;
j=1;
k=0;
while(j<strlen(p)-1)
{
if(k==0||p[j]==p[k]) //匹配的情况下,p[j]==p[k],next[j+1]=k+1;
{
j++;
k++;
next[j]=k;
}
else //p[j]!=p[k],k=next[k]
k=next[k];
}
}
二、求解nextval:
求nextval数组值有两种方法,一种是不依赖next数组值直接用观察法求得,一种方法是根据next数组值进行推理,两种方法均可使用,视更喜欢哪种方法而定。
本文主要分析nextval数组值的第二种方法:
模式串 a b a a b c a c next值 0 1 1 2 2 3 1 2 nextval值 0 1 0 2 1 3 0 2
1.第一位的nextval值必定为0,第二位如果于第一位相同则为0,如果不同则为1。
2.第三位的next值为1,那么将第三位和第一位进行比较,均为a,相同,则,第三位的nextval值为0。
3.第四位的next值为2,那么将第四位和第二位进行比较,不同,则第四位的nextval值为其next值,为2。
4.第五位的next值为2,那么将第五位和第二位进行比较,相同,第二位的next值为1,则继续将第二位与第一位进行比较,不同,则第五位的nextval值为第二位的next值,为1。
5.第六位的next值为3,那么将第六位和第三位进行比较,不同,则第六位的nextval值为其next值,为3。
6.第七位的next值为1,那么将第七位和第一位进行比较,相同,则第七位的nextval值为0。
7.第八位的next值为2,那么将第八位和第二位进行比较,不同,则第八位的nextval值为其next值,为2。
三、next和nextval比较
Next数组的缺陷举例如下:
比如主串是“aab…..” 省略号代表后面还有字符。
模式串“aac”
通过计算aac的next数组为012(另外,任何字符串的第二位字符的next总是1,因此你可以认为他固定为1)
当模式串在字符c上失配时,会跳到第2个字符,然后再和主串当前失配的字符重新比较,即此处用模式串的第二个a和主串的b比较
即aab aac
显然a也不等于b。然后会跳到1,接着比,然后又失配,直到最后才使主串后移一位。
而“aac”的nextval数组为002当在c失配时会跳到2,若还失配就直接跳到0,比next数组少比较了1次。
在如果模式串很长的话,那可以省去很多比较,因此你应该使用nextval数组。
KMP模式匹配算法改进:
后来有人发现其实KMP算法还是有缺陷的,比如主串S=“aaaabcde”,子串T=“aaaaag”,其next数组为012345;当i=5 ,j=5是“b”与“a”不匹配,此时j=next[5]=4,又发现j=4时,“b”与“a”不匹配,依次类推,直到j=next[1]=0;此时i++,j++,i=6,j=1从而我们发现中间有多余的判断,由于子串T中第2、3、4、5位置的字符都与首位的“a”相同,即可以用首位next[1]的值去取代与它字符相等的后续next[j]的值,即next数组改为000005,此时由i=5,j=5时“b”与“a”不匹配,此时j=next[5]=0;此时i++,j++得到i=6,j=1,即可省去中间的多余判断。因此我们需要改进next函数的求解方法。
相关文章
- (《机器学习》完整版系列)第13章 半监督学习——13.5 基于分歧的方法(多学习器间的差异、协同训练算法)
- 数据结构中八大排序算法
- Google Earth Engine ——消除影像色差直方图匹配算法(CDF累计分布函数)!
- OpenCV实现FloodFill泛洪填充算法的代码及相关函数详解
- 【c/c++】刷算法题时常用的函数手册 持续更新--
- 机器学习笔记之深度信念网络(三)贪心逐层预训练算法
- 《算法笔记》习题
- 【Matlab算法】粒子群算法求解一维非线性函数问题(附MATLAB代码)
- java 实现 DES加密 解密算法
- 算法入门到进阶(二)——STL和基本的数据结构(sort函数和next_permutation函数)
- 密码学系列之:NIST和SHA算法
- 整型数组处理算法(十一)请实现一个函数:线段重叠。[风林火山]
- 整型数组处理算法(十二)请实现一个函数:最长顺子。[风林火山]
- 华为OD机试 - 和最大子矩阵(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
- 华为OD机试 - 火星文计算(JavaScript) | 机试题+算法思路+考点+代码解析 【2023】
- C#函数之实现Lagrange插值算法
- 【历史上的今天】10 月 8 日:Netflix 创始人诞生;反向传播算法经典论文发表;Android 4.0 发布
- 我的软考之路(七)——数据结构与算法(5)之查找
- 35排序算法之合并排序
- JVM:这是一份全面 & 详细的 垃圾收集算法(GC) 学习指南
- 基于二维伽马函数的光照不均匀图像自适应校正算法
- 人工智能算法--启发式搜索与估值函数