KMP算法短短几行,却比较难理解,今天刷题碰到了,研究了一下午,拿出来跟大家分享一下
比如判断ABCABCGHA是不是ABCABCFABCD的字串
普通的思路是
这是进行比较的普通的思路,当比较到E不相等时,进行从第二位进行比较,如上图中的第二个。
KMP的精华在于如果目标字符串中有重复的,接下从重复的的下一个进行比较,如下图
既然是从重复的进行记录,那么就必须有数组进行记录重复的次数我们通常定义next[]数组,next数组的含义如下图
以上图的含义是从0开始,查找前面是否有与自己重复的,有的话记1,再有的话记2,比较的是前缀与后缀的大小,ABCAB,前缀有A,AB,ABCA后缀有B,AB,CAB,BCAB,当处于B的位置时,正好前缀AB与后缀AB相等,所以记为2,依次类推
含义明白了,直接上代码
void makeNext(char str[],int next[]){ int length = strlen(str); next[0] = 0; int index,int k;//一个是str的下标,k是最大前后缀的长度 for(index = 1,k = 0;index < length;++index){ while(k > 0 && str[index] != str[k])//前后缀不相等,比较之前相等的,见下图理解 k = next[k - 1]; if(str[index] == str[k]) //前后缀如果相等,将k加1,对应上图 ++k; next[index] = k; } }k = next[k-1]这一步最难理解,请看下图
每次比较就是从前面的寻找最大的前后缀长度,由于左侧与右侧相等,所以左侧的最大前后缀长度后面的那一个比如
str[2] = E与最后的E进行比较。
str[6]时,k = 0,所以str[11] k = 5;
next数组的作用以及代码就这样,下面看如何通过next数组与主字符串进行比较
bool kmp(int target[],int src[],int next[]) {//target 指的的主字符串 src指的是目标字符串,判断src是否在target中 int lengthTarget = strlen(target); int lengthSrc = strlen(src); makeNext(src,next); int i; int lengthOfCompare; for(i = 0,lengthOfCompare = 0; i< lengthTarget;++i){ while(lengthOfCompare > 0 && target[i] != src[lengthOfCompare]) lengthOfCompare = next[lengthofCompare - 1];//不等正好从 //前面最大的前后缀的下一个进行比较 if(target[i] == src[lengthOfCompare]) ++lengthOfCompare; if(lengthOfCompare == lengthSrc) return true; } }好了,就这些了,就这么简单