浅谈KMP算法
2017-10-21 14:01
169 查看
课上学了KMP算法之后有几个地方很是迷茫,课下就查了点资料,这里做下总结,今后忘了还能回来看一下。
首先,KMP算法的主要目的就是比较两个字符串时避免不必要的回溯。一个字符串可能会出现字符串头部和尾部有重复的现象,KMP算法就是根据这个现象,在比较字串时,不在简单地向后移一位,而是在后移时,跳过首位相同的部分再开始比较。例如:判断 ABCDABD 是否是 ABCDABEABCDABD 的子串,
ABCDABEABCDABD
ABCDABD
判断到第6位时 E 和 D 不同,但它的前两位 AB 和 子串的前两位 AB 相同,所以之后直接移动到
ABCDABEABCDABD
ABCDABD
所以这时子串和 E 比较的位的 C 的下标就等于 D 的前一位 B 的首位重复的位数
这里就需要对子串进行一个预处理,就是算出它的每一位对应的部分匹配值,也就是前后重复的位数,对于 ABCDABD 来说,就是 0000120,先上代码
#include <string>
#include <assert.h>
int* Next(string P){
int m = P.length();
assert( m > 0 ); //若 m = 0 则退出
int *N = new int[m];
assert( N != NULL );
N[0] = 0;
for(int i = 1; i < m; i ++){
int k = N[i - 1];
while(k > 0 && P[i] != P[k]){
k = N[k - 1];
}
if(P[i] == P[k]){
N[i] = k + 1;
}else{
N[i] = 0;
}
}
return N;
}其中 k 表示尾部要进行比较的上一位有几个字符重复,也代表接下来头部要进行比较的位的下标,k - 1 表示比较时头部重复部分最后一个字符的下标,i 表示第 i 个字符
我比较难理解的就主要是
循环出来后,条件应该为k == 0 || P[i] == P[k],之后的逻辑就简单了,如果前等于后,重复个数就加1,否则为0
KMP算法的代码就是
int KMPStrMartching(string T, string P, int startIndex){ //判断P是否为T的子串,是的话返回开始的下标
int *N = Next(P);
int lastIndex = T.length() - P.length();
if((lastIndex - startIndex) < 0)
return (-1);
int i = 0, j = 0;
for(i = startIndex; i < T.length(); i ++){
while(P[j] != T[i] && j > 0)
j = N[j - 1];
if(P[j] == T[i])
j ++;
if(j == P.length()){
delete N;
N = NULL;
return (i - j + 1);
}
}
delete N;
N = NULL;
return (-1);
}
首先,KMP算法的主要目的就是比较两个字符串时避免不必要的回溯。一个字符串可能会出现字符串头部和尾部有重复的现象,KMP算法就是根据这个现象,在比较字串时,不在简单地向后移一位,而是在后移时,跳过首位相同的部分再开始比较。例如:判断 ABCDABD 是否是 ABCDABEABCDABD 的子串,
ABCDABEABCDABD
ABCDABD
判断到第6位时 E 和 D 不同,但它的前两位 AB 和 子串的前两位 AB 相同,所以之后直接移动到
ABCDABEABCDABD
ABCDABD
所以这时子串和 E 比较的位的 C 的下标就等于 D 的前一位 B 的首位重复的位数
这里就需要对子串进行一个预处理,就是算出它的每一位对应的部分匹配值,也就是前后重复的位数,对于 ABCDABD 来说,就是 0000120,先上代码
#include <string>
#include <assert.h>
int* Next(string P){
int m = P.length();
assert( m > 0 ); //若 m = 0 则退出
int *N = new int[m];
assert( N != NULL );
N[0] = 0;
for(int i = 1; i < m; i ++){
int k = N[i - 1];
while(k > 0 && P[i] != P[k]){
k = N[k - 1];
}
if(P[i] == P[k]){
N[i] = k + 1;
}else{
N[i] = 0;
}
}
return N;
}其中 k 表示尾部要进行比较的上一位有几个字符重复,也代表接下来头部要进行比较的位的下标,k - 1 表示比较时头部重复部分最后一个字符的下标,i 表示第 i 个字符
我比较难理解的就主要是
while(k > 0 && P[i] != P[k]){ k = N[k - 1]; }这两行,翻译成中文就是 当一个子串满足去掉一个字符重复 k 个,加上这个字符却不重复 k + 1 个时,对于这个字符来说,它的重复个数等于当前头部重复部分最后一个字符的重复个数,满足条件则继续循环
循环出来后,条件应该为k == 0 || P[i] == P[k],之后的逻辑就简单了,如果前等于后,重复个数就加1,否则为0
KMP算法的代码就是
int KMPStrMartching(string T, string P, int startIndex){ //判断P是否为T的子串,是的话返回开始的下标
int *N = Next(P);
int lastIndex = T.length() - P.length();
if((lastIndex - startIndex) < 0)
return (-1);
int i = 0, j = 0;
for(i = startIndex; i < T.length(); i ++){
while(P[j] != T[i] && j > 0)
j = N[j - 1];
if(P[j] == T[i])
j ++;
if(j == P.length()){
delete N;
N = NULL;
return (i - j + 1);
}
}
delete N;
N = NULL;
return (-1);
}
相关文章推荐
- 浅谈kmp算法
- 浅谈扩展KMP算法
- 浅谈KMP算法
- 浅谈KMP算法
- 浅谈KMP算法——Chemist
- 浅谈KMP算法及实现
- BZOJ 3670 浅谈KMP算法的拓展应用
- 浅谈KMP算法的延伸
- 浅谈字符串匹配的KMP算法
- 浅谈字符串匹配算法—BF算法及KMP算法
- 浅谈KMP算法
- 浅谈KMP算法
- 浅谈属性动画简单使用之实现爱的贝塞尔曲线浪漫告白效果(三)
- 浅谈Linux 脚本 sh 和 ./ 的区别
- [原创] Web站点数据库分布存储浅谈
- 浅谈红外、蓝牙、WIFI、NFC等无线通信的发展
- 基于x86和JVM浅谈32bit与64bit的区别
- 浅谈css和div布局
- 浅谈工程师的调试法宝(四)---RTT的应用
- 浅谈Java中的hashcode方法