KMP算法是一种改进算法。
其核心是相等了,i 不用回退,j 退到 k 位置上。
通俗理解:就是因为他们有相同的部分那一部分由于 i 是回退到刚才位置的下一个位置,所以会造成错位,进而那一段相等的 j 就不会动,而 i 一直++,直到 i 与 j 的值相等,i 和 j 会继续走,进而 i 就会到原来从头到尾比较不相等的那个地方,j 就会在 k 值,现在就是要求 k 的值。
下面是例子:(竖线表示失配了而画的一条线,竖线的前面是匹配成功的)
abcdab|dabcdabc 主串 s串
|i
abcdab|c 子串 p串
j
上述就是到了失配的情况,以及 i 和 j 的位置情况。
在匹配成功的子串中找到两个最长的相等的真子串,这两个字串满足如下特点:
1.一个串以子串的开头作为开头
2.另一个串以失配前的最后一个字符作为结尾(Pj-1)
3. k 正是子串的长度
KMP算法代码如下:
#include <stdio.h>
#include <string.h>
#include <assert.h>
#include <malloc.h>
static int* GetNext(const char* str)
{
int len = strlen(str);
int* next = (int*)malloc(sizeof(int) * len);
next[0] = -1;
next[1] = 0;
int j = 1;
int k = 0;
while (j+1 < len)
{
if ((k==-1)||str[k] == str[j])
{
next[++j] = ++k;
/*next[j + 1] = k + 1;
j = j + 1;
k = k + 1;*/
}
else
{
k = next[k];
}
}
return next;
}
int KMP(const char* str, const char* sub, int pos)
{
assert(str != NULL && sub != NULL);
if (str == NULL || sub == NULL || pos<0 || pos>strlen(str))
return -1;
int lenstr = strlen(str);
int lensub = strlen(sub);
int i = pos;
int j = 0;
int* next = GetNext(sub);
while (i < lenstr && j < lensub)
{
if (j == -1 || str[i] == sub[j])
{
i++;
j++;
}
else
{
//i不用回退
j = next[j];
}
}
if (i >= lensub)
return i - j;
else
return -1;
}
int main()
{
const char* str1 = "abcdabdabcdabde";
const char* str2 = "abd";
printf("%d\n", KMP(str1, str2, 0));//4
printf("%d\n", KMP(str1, str2, 7));//11
return 0;
}