KMP优化
来源:互联网 发布:学生管理系统java 编辑:程序博客网 时间:2024/06/05 10:36
KMP优化
KMP算法是有优化版本的,之前写过文章简单的讨论了基本的KMP算法思想,但是对于一些含有连续重复字符的字符串,会出现多次冗余的比较。
例如:字符串S=“aaababa”和模式串P=“aaac”比较时,会出现多次的不必要的比较,这个我会在下面细说。
Next数组重定义
我们首先要解决的问题就是next数组的意义,之前的我写的KMP文章里面,next数组的意义是:字符串真子串中既是前缀串同时又是后缀串中最长的那个子串的长度。例如还是模式串P=“aaac”,其对应的next数组值为:
为了优化KMP,我们要换一种写KMP代码的思路,参考网上的代码及next数组的定义,我们首先就是需要重新改变一下next数组,我们现在定义next[i]为:表示匹配串在i处如果匹配失败下次移到的位置。 如果第一个字符就匹配不成功,那么没有地方移动,我们就定义next[0] =-1.
于是模式串P=“aaac”对应新的next数组为:(不考虑优化)
相当于把之前的next数组整体向右移了1位,并在开始处加入-1,重新定了next数组之后,我们的KMP算法该怎么写呢?如下:
//求next数组void getNext(){ int i = 0; //pattern串的下标 int j = -1; // next[0] = -1; while (i < pattern_len - 1) { if (j == -1 || pattern[i] == pattern[j]) { ++i; ++j;//i,j相加之后pattern[0..j-1]和pattern[i-j....i-1]是相等的 next[i] = j;//pattern[i]位字符匹配不成功时应该重新回到pattern[j]位进行匹配 } else j = next[j]; }}
int kmp(){//字符串比较过程 int i = 0, j = 0; str_len = strlen(str); getNext(); // 计算next数组; while (i < str_len && j < pattern_len) { if (j == -1 || str[i] == pattern[j]) { ++i; ++j; } else j = next[j]; } if (j >= pattern_len) return i - pattern_len; else return -1;}
Next数组优化
重新定义了next数组实现代码之后,我们发现这和之前的KMP算法(算法导论上的实现方式)实现效果本质是一样的,出现不匹配时充分利用了之前的已匹配的信息,然后将字符串进行转移,但是还是会发生一开始提到到的字符串S=“aaababa”和模式串P=“aaac”多次冗余比较的问题。我们仔细来看一下,现在的比较过程:
- 当pattern[3] = ‘c’ 和 s[3] = ‘b’发生了不匹配的时候,我们需要移动pattern的比较index,这时候移动到了next[3] = 2
- pattern[2] = ‘a’ 和 s[3] = ‘b’仍然不匹配,继续移动,移动到next[2]=1
- pattern[1] = ‘a’ 和 s[3] = ‘b’仍然不匹配,继续移动….移动到next[1]=0
- …………………..好累
出现这样的原因是因为pattern的前三个字符都是a,第四个字符c和前面的字符都不相同,所以当第四个字符不匹配的时候,前面都没有必要再比较了 , 所以说我们在求next数组的时候还有没利用的信息。当不匹配发生移动的时候,我们可以判断当前pattern[i]字符与pattern[j](也就是假想的要移动到的index)是否相同
- 若不相同,和之前是一样的next[i]=j(下一次匹配pattern[j])
- 若相同,那么就直接next[i] = next[j] (在求next数组的过程中避免了多次冗余的比较)
实现代码如下(参考网上):
//优化算法,求next数组的值void getNext2(){ int i = 0; //pattern串的下标 int j = -1; // next[0] = -1; while (i < pattern_len - 1) { if (j == -1 || pattern[i] == pattern[j]) { ++i; ++j; if (pattern[i] != pattern[j]) //正常情况 next[i] = j; else //特殊情况,这里即为优化之处。考虑下AAAB, 防止4个A形成012在匹配时多次迭代。相当于next[3]=next[2]=next[1]=next[0]=-1 next[i] = next[j]; } else j = next[j]; }}
此时匹配的过程如下:
此时不需要多次冗余的比较….而最终的KMP比较算法是不变的,这里就不再重复给出。
总结
本文给出了优化版的KMP算法,之前的算法导论版本的KMP代码的优化实现暂时还没想出…. 而本文优化的关键之处是改变了之前的next数组的意义,从之前的真子串中既是前缀串同时又是后缀串中最长的那个子串的长度 转变为求发生不匹配时要移动的新位置,两者是相同的,只是最后的value值不同。
记录一下,以便以后快速回忆起来。
参考链接:
http://www.acmerblog.com/kmp-algorithm-2-4411.html
- KMP优化
- KMP算法及其优化
- KMP算法优化
- KMP算法的优化
- KMP算法及其优化
- kmp算法的优化
- KMP算法及其优化算法
- KMP 算法并非字符串查找的优化
- 使用C# 优化KMP字符串匹配算法
- Kmp字符匹配算法优化C++实现
- KMP模式匹配算法--未优化
- bzoj1009 GT考试 KMP+矩阵优化DP
- KMP算法next数组计算方法的优化
- KMP算法——C++优化实现
- KMP模板及next 数组优化
- 字符串查找(KMP算法及其优化)
- C++实现KMP算法(优化版)
- KMP算法理解,and优化(待发)
- MIT HAKMEM算法分析
- 用Java实现的帧动画效果
- Linux下netstat和vmstat以及ifstat的使用
- (模板)最大权闭合图
- Tomcat简介、安装以及启动
- KMP优化
- 排序算法(一)
- JavaScript内核笔记08-函数式编程
- apue 习题6.3
- final关键字讲解
- CListCtrl控件详解(一)
- 阿里2016面试笔试题目之棋盘走法
- 如何在activity中获取我们想要的view的宽高?
- 用switch写一个区分输入成绩等级的小程序