BF算法就是我们最基本的求解字符串匹配的算法,算法的时间复杂度为O(M*N),空间复杂度为O(1),具体过程如下:
| 串 | 第一次 | 第二次 | 第三次 | 第四次 |
|---|---|---|---|---|
| 模式串S[i] |
abcababc |
abcababc |
abcababc |
abcababc |
| 匹配串T[j] |
ababc |
ababc |
ababc |
ababc |
可以看到在第三次匹配失败的时候,我们要回溯,直接S串直接i+=1,然后T串j=0从头继续开始。这样复杂度就比较高了。
而KMP算法就是为了解决BF算法的复杂度比较高而出现的,KMP算法的时间复杂度为O(M+N),空间复杂度为O(N),具体过程如下:
| 串 | 第一次 | 第二次 | 第三次 | 第四次 |
|---|---|---|---|---|
| 模式串S[i] |
abaababc |
abaababc |
abaababc |
abaababc |
| 匹配串T[j] |
ababc |
ababc |
ababc |
ababc |
| 第四次 | 第五次 | 第六次 | 第七次 | 第八次 |
abaababc |
abaababc |
abcababc |
abcababc |
abcababc |
ababc |
ababc |
ababc |
ababc |
ababc |
在第四次匹配失败后,不进行回溯,而是直接对匹配串进行下一个匹配,是因为前面已经把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