kmp算法小结.
目录
前言:
对于文本程序来说,找出一个子串在文本中的位置是特别重要的,我们称那个子串为模式串(pattern),然后我们称寻找的过程为:模式匹配(string match)。
kmp算法就是一种串的模式匹配算法.
即:假设我们有两个字符串T和P, 找到P在T中的位置.
我们最容易想到的是:
从主串的指定的起始位置字符开始和模式第一个字符比较,如果相等,则继续比较下一个字符,如果不等,则从主串的下一个字符开始和模式的第一个字符开始比较,以此类推,直到模式串所有字符都匹配完成,则匹配成功,否则,匹配不成功。
然而值得一提的是这种算法在处理一些较长的串的时候会消耗很长时间,为了降低时间复杂度我们下边开始简绍今天的主题 KMP算法.
简介:
kmp算法可以理解为对应子串字符建立一个数组,一般用next命名.
例如:子串 P:a,b,a,b,c;就可以建立数组 如下.
int next[5];
之后再通过研究子串P本身的字符顺序去将数组赋值.(这个过程只和子串P本身有关,和母串T无关.)
整个kmp算法最精华的部分就是next数组的获取,我们将在下边去详细的描述怎样获取next数组对应的数字.
假设子串P和他对应的next数组如下:
然后从主串的指定的起始位置字符开始和模式第一个字符比较,如果相等,则继续比较下一个字符,如果不匹配则拿next数组在该不匹配位置为下标的数组的值当做P的下标重新匹配.
例如:
观察长图可以发现在字符串下标为3的位置两字符不同,匹配失败,然后观察到next数组下标为3的位置对应的数字为1,所以按照前边的描述将1作为子串P的下标和母串T再次进行匹配.如下图:
然后可以观察到仍然匹配失败,重复上边的步骤将母串T的a和子串P下标为0的字符开始匹配,即:
此次结果为匹配成功,然后去匹配两个串的下个字符
结果为匹配失败,然后重复之前的过程.结果如下:
将P的0下标位置和T比较.此次匹配之后next数组对应数值为-1,可以假设数组P前边还有一个下标为-1的位置,将-1与母串T的c对齐,即可以看成将子串P整体向右位移一位,也就是开始比较母串的下一位字符.
然后再重复之前的过程就会发现结果如下:
可以发现母串可以和子串完全匹配,此时只需要记录母串相应下标即可.但我们假设母串T里边可能有多个子串P相应的序列,如果我们想要把所有相应数列位置找到此时应按照子串P的下标对应的next数组的值进行操作.即next[4]=2,将子串P下标为2的字符和母串T刚才位置的c进行比较,如下:
此时发现c与a不匹配,然而如果再将子串P向右拉动的话母串T就没有位置了,所以可以得出结论母串T里边只有一个和子串P对应的子序列.
next数组的获取:
还拿我们刚才的子串P做例子.
首先需要找出该串的所有前缀序列,如下所示:
然后将每个前缀当做独立的字符串,然后去找出除它们本身的最长公共前后缀.
例如 abab 除本身外的最长公共前后缀为 ab,长度为2.
依次重复找出所有子序列的值如下.
然后给最后一个序列删除,在最前边补-1(不设0的原因是以区分别的0).
我们将如下图红框圈着的部分作为子串P对应的next数组的值.
即对照关系为:
所以子串P对应的next数组为-1,0,0,1,2;
代码如下:
void GetNext(char* p,int next[])
{
int pLen = strlen(p);
next[0] = -1;
int k = -1;
int j = 0;
while (j < pLen - 1)
{
//p[k]表示前缀,p[j]表示后缀
if (k == -1 || p[j] == p[k])
{
++k;
++j;
next[j] = k;
}
else
{
k = next[k];
}
}
}
小结:
总的来说kmp算法主要分为两个部分。
1.next数组的建立.
2.next数组在和母串匹配时的使用.
所以说只要掌握了next数组可以说kmp算法就掌握了kmp算法的核心.
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)