BF算法就是我们最基本的求解字符串匹配的算法,算法的时间复杂度为O(M*N),空间复杂度为O(1),具体过程如下:
串 | 第一次 | 第二次 | 第三次 | 第四次 |
---|---|---|---|---|
模式串S[i] |
a bcababc |
ab cababc |
abc ababc |
ab cababc |
匹配串T[j] |
a babc |
ab abc |
aba bc |
a babc |
可以看到在第三次匹配失败的时候,我们要回溯,直接S串直接i+=1,然后T串j=0从头继续开始。这样复杂度就比较高了。
而KMP算法就是为了解决BF算法的复杂度比较高而出现的,KMP算法的时间复杂度为O(M+N),空间复杂度为O(N),具体过程如下:
串 | 第一次 | 第二次 | 第三次 | 第四次 |
---|---|---|---|---|
模式串S[i] |
a baababc |
ab aababc |
aba ababc |
abaa babc |
匹配串T[j] |
a babc |
ab abc |
aba bc |
abab c |
第四次 | 第五次 | 第六次 | 第七次 | 第八次 |
abaa babc |
abaa babc |
abcab abc |
abcaba bc |
abcabab c |
ab abc |
a babc |
ab abc |
aba bc |
abab c |
在第四次匹配失败后,不进行回溯,而是直接对匹配串进行下一个匹配,是因为前面已经把aba匹配过了,知道前一个也是a不需要再次进行匹配,这个就是通常所说的KMP算法。而在匹配失败后到底对哪个进行再次匹配,也就需要我们求next[j]数组了。
next数组存放的是,当匹配失败后,需要跳转到哪个字符再次进行匹配。
求的方法,手算:
例子(ababc)的next数组为:[-1 0 0 1 2].
i = 0, j=-1, next[0]=-1, next[1]=0;
next[2] = next[1+1];
next[1] = 0
T[1] != T[0];
则next[2] = next[1] = 0;
next[3] = next[2+1];
next[2] = 0;
T[2] == T[0] (T[2] = a, T[1] = b)
则next[3] = next[2]+1;
next[4] = next[3+1];
next[3] = 1;
T[3] == T[1];
则next[4] = next[3]+1 = 2;
以上是手算的解法,代码求解比较简单。
如下
void getNextval(char *p,int *next) { int j,k; next[0]=-1; j=0; k=-1; while(j<strlen(p)-1) { if(k==-1||p[j]==p[k]) //匹配的情况下,p[j]==p[k] { j++; k++; next[j]=k; } else //p[j]!=p[k] k=next[k]; } }
改进的之后的next数组效率更高,但是我暂时还没找到如何手算,假如你知道,请评论给我,非常感谢。但是代码实现非常简单,就是在第一次判断之后,再进行一次判断。
代码如下:
void getNext(char *str, int *next){ int i = 0; int length = (int)strlen(str); int j = -1; next[0] = -1; while (i < length-1) { if (j == -1 || str[i] == str[j]) { ++i; ++j; if (str[i] != str[j]) { next[i] = j; }else{ next[i] = next[j]; } }else{ j = next[j]; } } }
而KMP整个的代码实现如下:
int KMP(const char *src, const char *tar, int *next){ int srcLength = (int)strlen(src); int tarLength = (int)strlen(tar); int i = 0, j = 0; while (i < srcLength && j < tarLength) { if (j == -1 || src[i] == tar[j]) { ++i; ++j; }else{ j = next[j]; } } if (j >= tarLength) { return i-tarLength; }else{ return -1; } }
原文地址:http://blog.csdn.net/alps1992/article/details/40301207