有关KMP算法的介绍
众所周知,KMP算法是用来处理字符串相关问题的算法,在KMP算法之前有我们熟悉的暴力算法(朴素算法)如下:
bool Cmp(string a,string b){ // a是总串 b是模式串(寻找的子串)
int length2=b.length;
for(int i=0;i<(a.length-b.length)+1;i++){
if(a.substr(i,length2)==b) //如果a的从i开始 length2长度之后和b串匹配
return true;
}
return false;
}
因为这么跑的话时间复杂度是O(M*n) 因为每一个小循环都要比较n个数,大循环要执行m-n+1次数 所以总的是m*n 因此在这个基础上产生了KMP算法O(M+N)
KMP算法的核心思想就是在朴素算法的基础上修改了总的字符串前进的方式以及模式串的前进方式(因为朴素算法的前进方式是 模式串指针归为原位,总字符串前移一个位置。)但KMP的核心思想是,如果模式串的第j个字符不匹配,总字符串的指针I不变 模式串的指针j指向next[j]的位置之后比较a[i]和b[j];而计算next的方法如下:我们以aaaab为例
序号 | 1 | 2 | 3 | 4 | 5 |
对应字母 | a | a | a | a | b |
next[i] | 0 | 1 | 2 | 3 | 4 |
等我们计算完对应的next之后就可以构架后续代码了
//这里假设next[]设置为全局变量
//指导书上用的起始位置都是1 方便对应next
bool kmp(string a,string b){ //a是总串 b是模式串
int j=1;
for(int i=1;i<=(a.length-b.length)+1;){
if(a[i]==b[j]){
i++;
j++;
}
else{
j=next[j];
if(j==0){//教科书把本次条件判断放到第一个if中 用'|'连接
j++;
i++;
}
}
if(j>=b.length)
return true;
else
return false;
}
}
后序还学习了kmp的改进代码 进行的改动t就是增加了一个nextval 数组,因为在一些时候会存在特殊情况,例如上述提到的aaaab样例, 如果第三个不匹配 那个我们可以确定总字符串中第三个肯定不是a 但由于我们设计的next数组,我们会让j跳到next[j]也就是next[3]处,此时next[3]等于2 然后 i仍然不变,可以确定地是a[i]一定不等于a 但是当j=next[3]=2的时候 b[j]是等于a的因此两个一定不相等,又要多进行一次判断。会使时间增加。因此提出了一个nextval的数组,用来优化next数组
计算方式如下:如果序号为i的next[i]所指的序号的字母和i的字母一样 则nextval[i]=nextval[next[i]] 否则就不变.
序号 | 1 | 2 | 3 | 4 | 5 |
字母 | a | a | a | a | b |
next[i] | 0 | 1 | 2 | 3 | 4 |
nextval[i] | 0 | 0 | 0 | 0 | 4 |