KMP算法(代码+图解证明)
2016-09-08 17:09
281 查看
KMP算法用于字符串匹配,是相较于朴素字符串匹配。所谓朴素字符串匹配就是从头到尾开始一个位置一个位置匹配,当前位置匹配失败则会从下一个位置开始继续匹配。
KMP算法则是可以跳,能往前跳多远就往前跳多远。我们知道算法尽量要简化计算、去冗余、记忆搜索。KMP就是利用了去冗余的思想往前跳到某一位置继续匹配。而中间未匹配的丝毫不会有影响,这要归结于我们next数组的定义。
所谓next数组中next[i]就是记录如果当前位置位置不匹配,字符串可以往前跳多远进行重新匹配。所以next[i]就是计算i之前字符串的最大回文长度(就是前缀和后缀相等的最大长度)。中间跳跃的点都是不用匹配的点,这个可以证明。
如图,我们中间跳过的位置,如果存在有用的,即b'>b的长度。这种情况反证了我们b计算错误,也即我们next数组没求最长的,也就是没求对。故而,跳过的就是没用的。
那么指导跳跃的next数组的求法如下图所示。
上图演示的是next[i]这一位的计算方法,使用到了递归。这些说明白了,直接上代码。
#include<iostream>
#include<string>
using namespace std;
int * getNextArray(string ms) {
if (ms.length() == 1) {
int *a=new int[1];
a[0]=-1;
return a;
}
int* next = new int[ms.length()];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < ms.length()) { //next数组从2之后大于等于0
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
//s是原串,m是模式串
int getIndexOf(string s, string m) {
if (s == "" || m == "" || m.length() < 1 || s.length() < m.length()) {
return -1;
}
int si = 0;
int mi = 0;
int* next = getNextArray(m);
while (si < s.length() && mi < m.length()) {
if (s[si] == m[mi]) {
si++;
mi++;
} else if (next[mi] == -1) {
si++;
} else {
mi = next[mi];
}
}
return mi == m.length() ? si - mi : -1;
}
KMP算法其实不难,仔细研究下就可以理解了。
KMP算法则是可以跳,能往前跳多远就往前跳多远。我们知道算法尽量要简化计算、去冗余、记忆搜索。KMP就是利用了去冗余的思想往前跳到某一位置继续匹配。而中间未匹配的丝毫不会有影响,这要归结于我们next数组的定义。
所谓next数组中next[i]就是记录如果当前位置位置不匹配,字符串可以往前跳多远进行重新匹配。所以next[i]就是计算i之前字符串的最大回文长度(就是前缀和后缀相等的最大长度)。中间跳跃的点都是不用匹配的点,这个可以证明。
如图,我们中间跳过的位置,如果存在有用的,即b'>b的长度。这种情况反证了我们b计算错误,也即我们next数组没求最长的,也就是没求对。故而,跳过的就是没用的。
那么指导跳跃的next数组的求法如下图所示。
上图演示的是next[i]这一位的计算方法,使用到了递归。这些说明白了,直接上代码。
#include<iostream>
#include<string>
using namespace std;
int * getNextArray(string ms) {
if (ms.length() == 1) {
int *a=new int[1];
a[0]=-1;
return a;
}
int* next = new int[ms.length()];
next[0] = -1;
next[1] = 0;
int pos = 2;
int cn = 0;
while (pos < ms.length()) { //next数组从2之后大于等于0
if (ms[pos - 1] == ms[cn]) {
next[pos++] = ++cn;
} else if (cn > 0) {
cn = next[cn];
} else {
next[pos++] = 0;
}
}
return next;
}
//s是原串,m是模式串
int getIndexOf(string s, string m) {
if (s == "" || m == "" || m.length() < 1 || s.length() < m.length()) {
return -1;
}
int si = 0;
int mi = 0;
int* next = getNextArray(m);
while (si < s.length() && mi < m.length()) {
if (s[si] == m[mi]) {
si++;
mi++;
} else if (next[mi] == -1) {
si++;
} else {
mi = next[mi];
}
}
return mi == m.length() ? si - mi : -1;
}
KMP算法其实不难,仔细研究下就可以理解了。
相关文章推荐
- kmp算法的c代码实现
- c++代码测试-vector赋值, 证明是深度赋值
- KMP算法代码
- VS2008 JS调试和Silverlight 后台代码调试 相互影响的问题。---自己做实例证明
- [漫画图解] 重构代码异味
- 模式串匹配之KMP算法代码及注释
- 我写的KMP算法代码
- KMP算法的C++实现代码
- 图解VS2008单元测试及查看代码覆盖率
- KMP算法C代码描述
- 经典证明:Chaitin定理 不可能编程判断代码的最简性
- 让DBA去写数据访问层(DAL)代码--PDF.NET数据开发框架之SQL-MAP使用图解
- 模式匹配的KMP算法代码
- 图解VS2008单元测试及查看代码覆盖率
- KMP算法C++代码
- 在UltraEdit中运行SAS代码-配置图解
- Knuth Morris Pratt (KMP)算法的证明及实现代码
- 图解VS2008单元测试及查看代码覆盖率(转)
- KMP算法中核心的代码
- 【HDU4313】Matrix 多校 解题报告+AC代码+思路+算法正确性证明,此为Kruskal贪心简单版本,恶心版本稍后放出【目标达成 0.2%】