原链接:http://www.nowcoder.com/live/2/5/1,本文内容由牛客网左老师的讲课内容整理而来。
KMP算法用于字符串匹配,其时间复杂度为o(n+ m),其中n为原字符串的长度,m为匹配字符串的长度,一般n > m,所以其时间复杂度也可以认为是o(n)
如假设有字符串str,其长度为n,匹配串是match,其长度是m,求match在str中第一次出现的位置。
KMP算法中最重要的是跳转数组next[m],其表明了匹配串的特征,大小和match相同,其中其next[i]表示match中从下标0到i - 1的字符串的最长前缀和后缀相等的长度大小,注意,前缀不能包括下标为i-1的字条,后缀不能包括下标为0的字符,如
next数组中规定next[0] = -1(因为其没有前缀和后缀),next[1] = 0(因其前缀是下标为i-1的字符,后缀又是下标为0的字符,违反了next定义,所以其为0)。
对于图中match= {1,2,3,1,2,3,a,a}来说,next[5]就是其下标0-4之间的字符串的特征,即其前缀与后缀相等的最长字符串为12,字符串长度为2,所以next[5] = 2;
对于图中match= {a,b,a,b,a,b,a}来说,next[6]就是match数组中其之间的字符串的特征,即其前缀和后缀最长的字符串为abab,如图中标记的所示,字符串的长度为4,所以next[6] = 4,其它值以此类推。
next数组的求法:
对于next[i] ,假设其next[i-1]已经求出,即第i-1位置上的最长前缀和后缀长度已知,假设为next[i-1] = j,如图中红色圈圈所示,a为其前缀的下一个字符,也即是match[j] = a,如果match[i-1] == a,则可以得出:next[i] = next[i - 1] +1,如果match[i - 1] != a,则比较match[i - 1]与a所在位置的前缀(第一个墨绿色圈圈)的后一个字符b(match[next[j]] = b)是否相等,如果相等,则next[i] = next[j] + 1,不相等,继续此过程,...,当next[j] == 0了,则next[i]只能是0;
代码见最后
匹配过程:
如红色箭头所示:当匹配到str中下标j位置,match中下标为5的位置时失配了,这时,next[5] = 2,则从match[2]与str[j]进行比较,依次进行下去即可,....
代码如下: (vs2010调试通过)
1 #include <stdio.h> 2 #include <string.h> 3 #include <stdlib.h> 4 5 char *GetNext(char match[]) 6 { 7 char *next; 8 int cn,pos; 9 next = (char *)malloc(sizeof(char) * strlen(match)); 10 11 next[0] = -1; 12 next[1] = 0; 13 14 //cn表示前一个位置的next值 15 //即是,如当前需要求next[i],则cn = next[i - 1] 16 cn = 0; 17 pos = 2; 18 while(pos < strlen(match)){ 19 if(match[pos - 1] == match[cn]) 20 next[pos++] = ++cn; 21 else if(cn > 0) 22 cn = next[cn]; 23 else 24 next[pos++] = 0; 25 } 26 return next; 27 } 28 //进行字符串匹配 29 int GetIndexOf(char str[],char match[]) 30 { 31 int sl,ml,is,im; 32 char *next; 33 sl = strlen(str); 34 ml = strlen(match); 35 next = GetNext(match); 36 im = is = 0; //is、im分别表示原字符串、匹配字符窜中的下标 37 while(is < sl && im < ml){ 38 if(str[is] == match[im]){ 39 is++; 40 im++; 41 } 42 else if(next[im] == -1) 43 is++; 44 else 45 im = next[im]; 46 } 47 48 return (im == ml) ? is - im : -1; 49 } 50 int main() 51 { 52 int res; 53 char str[1024]; 54 char match[512]; 55 56 gets(str); 57 gets(match); 58 res = GetIndexOf(str,match); 59 if(res >= 0) 60 printf("成功匹配,其位置:%d ",res); 61 else 62 printf("匹配失败 "); 63 64 system("pause"); 65 return 0; 66 }