KMP算法中的next数组
来源:互联网 发布:程序员实用算法 编辑:程序博客网 时间:2024/06/09 14:35
我们经常会有这种需求,比如在字符串goodgoogle
中去查找google
这个子串,这种子串的定位操作通常称作串的模式匹配。
朴素的模式匹配算法
对于以上问题,最容易想到的方式当然是暴力破解了,我们可能写出如下代码:
12345678910111213141516171819202122232425262728293031
/*朴素的模式匹配算法*/int getIndex (const char *pStr,const char *cStr) {int pLen = strlen(pStr);int cLen = strlen(cStr);int pos = -1,i = 0,j = 0;while (i < pLen && j < cLen) {if (pStr[i] == cStr[j]) {i ++;j ++;} else {i = i - j + 1; // 回到上一次开始匹配的下一个位置j = 0;}}if (j = cLen) {pos = i - cLen;}return pos;}int main () {char *p = "goodgoodgoodgoogle";char *c = "google";int pos;pos = getIndex(p, c);printf("pos: %d\n", pos); // 12return 0;}
以上算法,简单地说,就是对依次用主串的每一个字符作为开头,与子串字符进行匹配。主串做大循环,子串做小循环,直到匹配成功为止。
它的时间复杂度为O(n + m)
,其中n为主串长度,m为子串长度。
KMP算法
朴素的模式匹配算法是低效的,于是三位前辈——D.E.Knuth、J.H.Morris、V.R.Pratt就研究出了KMP算法,有人称看毛片算法。
KMP算法是一个模式匹配算法,可以大大避免重复遍历的情况。
它具有以下特点:
- 主串的i值不回溯。
- 子串的j值会在不匹配时发生回溯,回溯的位置为next[j]。
- next数组表示:在子串与主串在某处失配时,子串j应该回溯的位置,即next[j]。
- 而next[j]的值取决与子串位置j之前的字符串中,前后缀的相似度。
下面一张图辅助理解:
next数组求解
KMP算法的核心就是next数组,有了一个子串的next数组,KMP算法也就很容易实现了!
那么给定一个子串,如何求出其next数组呢?
要解决这个问题,我们需要谨记next数组的相关概念:
它的长度和子串长度相同,它的每个值说明了在子串和主串失配时,应该从子串的哪个位置开始下次匹配。而next[j]的值,就是子串在j位置之前的字符串的前后缀相似度。
它的求解过程可以图解如下:
代码实现
有了next数组,就可以上代码啦,代码虽然写的不太简洁,但是问题可以解决了:
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556
/*返回子串next数组*/int * getNext (const char *c) {int cLen = strlen(c);int next[cLen];int *p = next; // 用于返回,因为next不能用作返回返回值int i = 0; // 前缀的下标int j = 1; // 后缀的下标next[0] = -1;while (j < cLen) {if (c[i] == c[j-1]) { // 如果前后缀相等,前后缀相似度加1next[j] = next[j-1] + 1;i ++;j ++;} else {i --; // 如果前后缀不相等,i值回溯if (i < 0) { // 如果i回溯到0位置依旧不等,j指向下一个位置next[j] = 0;i ++;j ++;}}}return p;}/*KMP模式匹配算法*/int getIndex (const char *p, const char *c) {int pLen = strlen(p);int cLen = strlen(c);int pos = -1, i = 0, j = 0;int *next = getNext(c); // 对c串进行分析,得到其next数组while (i < pLen && j < cLen) {if (j == -1 || p[i] == c[j]) { // 如果j=-1,代表第0个位置不匹配,则i和j都需要向后加1i ++;j ++;} else {j = next[j];}}if (j == cLen) {pos = i - cLen;}return pos;}int main () {char *p = "aaaaabcdefaaaaax";char *c = "aaaaax";int pos;pos = getIndex(p, c);printf("pos: %d\n", pos); // 10return 0;}
以上就是完整的KMP算法的实现,不过KMP算法还有可以优化的地方,后续补充。
阅读全文
0 0
- KMP算法中的next[]数组
- KMP算法中的next数组
- KMP算法中的next数组
- KMP算法中的next数组求解
- KMP算法中的NEXT数组的应用
- KMP算法中的Next数组的求取
- KMP算法中的next数组解析
- KMP 算法 next数组
- KMP算法--next数组
- KMP算法+NEXT数组
- KMP算法next数组
- KMP中的next数组
- KMP算法中的next数组的两种算法求解
- KMP算法的next数组
- KMP算法Next数组计算
- KMP算法Next数组计算
- kmp算法之next数组
- KMP算法求next数组
- JS:问题记录一
- C# List<T>用法
- tyvj 1387 迷你火车头
- 滚动页面时DIV到达顶部时固定在顶部(jq实现)
- Docker 自修笔记(二)
- KMP算法中的next数组
- 关于面向对象的浅层次理解。
- 5709
- 配置Maven时报错
- Xcode中模拟器消失的解决方案
- 1067. 试密码(20)
- Lua中的栈概念
- GY521-MPU6050使用笔记-STM32F103VE
- 1 微信如何搜索附近的人?