今天学习了KMP算法,相较于暴力匹配来说,KMP算法能够节省大量的时间,是一类想当精妙的算法,为了防止以后遗忘,特写此博客:
什么是KMP算法?
KMP算法是的作用是判断字符串s2是否为s1的子串,并返回下标,作用类似于strstr,但KMP的好处在于速度很快,这一点不仅在竞赛的时候拥有极大的优势,在项目设计的匹配算法中也有应用。
KMP算法的实现
①:前缀后缀的转移,KMP算法的核心在于字符串前后缀的一个跳转,以此来节省时间,在字符串的比较中若是后缀后的字符匹配不能,就跳转到前缀来继续匹配,就相当于从原本的一个一个匹配变成了一块一块匹配,速度当然会快很多。
②:预处理,通常匹配需要字符串和不同的文本进行不断的匹配,因此我们需要一个数组来存字符串的前后缀情况,在此开一个数组pre来储存,作用是记录每个字符串位置之前最大的相同前后缀,通过储存的数字来告诉电脑在字符匹配不成功时该从哪开始重新匹配,有了这个pre,不管要和多少文本匹配都没有关系。
③:pre的构造,这个相当于是字符串自身前缀后缀的一个匹配过程,因此需要调用自身,匹配失败就退而求其次,pre-1,代码实现:
int pre[110];
void get_pre(char *s){
int i=0;
int j=-1;
pre[0]=-1;
int len=strlen(s);
while(i<len-1){
if(j==-1||s[i]==s[j]){
i++;
j++;
pre[i]=j;
}
else{
j=pre[j];
}
}
}
④:与字符串的匹配,有了以上的基础,这个就显得相当简单,就是用pre去实现前后缀的移动,代码如下:
int KMP(char *s1,char *s2){
int i=0,j=0;
int len1=strlen(s1),len2=strlen(s2);
while(i<len1&&j<len2){
if(j==-1||s1[i]==s2[j]){
i++;
j++;
}
else{
j=pre[j];
}
}
if(j>=len2){
return i-len2+1;
}
else{
return -1;
}
}
最后,重申一下这篇博客是写给我自己的,如果有幸能为读者您所看到并且从中领悟到什么,我将不胜荣幸。