KMP 算法查找在文本中是否出现过某个字符或串。算法核心在于是状态转移,利用以前的信息去掉多余的比较。
example: 当一个串ababce在和ababd匹配到ababc的时候失败了,现在要比较的是c(abce中的c)和a(abab中的第二个a)比较。
为什么?
因为abab重复出现c出匹配失败,那么至少ab是匹配成功的。就是说长度为4的模式串的前缀等于后缀的最大长度为2.
所以我们可以得到这样的一个失败函数:(对于模式串来说)(前缀不能等于已经匹配了的字符长度)
i = 0, next = 0; //已经匹配了0个字符,前缀等于后缀的最大长度是0
i = 1, next = 0; //已经匹配了1个字符,前缀等于后缀的最大长度是0(也可以说正在匹配第i个字符)
所以用递推地方法,如果i位置的字符等于已经匹配的字符的最大长度的下一个字符,我们就得到了已经匹配了i+1个字符的
最大匹配长度;否则,沿着失败边走。
举个例子:
对abababa求失败函数:
初始化next[0] = next[1] = 0; //已经匹配了0个和1个字符的失败函数都是0
abababa
00
i= 1;正在匹配 b 字符,失败next[2] = 0;
i = 2 正在匹配a字符,成功,next[3] = 1;
i = 3 正在匹配b字符,成功,next[4] = 2;
i = 4 正在匹配a字符,成功,next[5] = 3;
i = 5 正在匹配b字符,成功,next[6] = 4;
i = 6 正在匹配a字符,成功,next[7] = 5;
char s[10000];
char p[1000];
int next[1005];
void get_fail()
{
next[0] = next[1] = 0;
int j;
for (int i = 1; p[i]; i ++) //正在匹配第i个字符(已经匹配了i个字符)
{
j = next[i];
while (j && p[i] != p[j]) j = next[j]; //匹配失败沿着匹配边走
next[i+1] = p[i] == p[j] ? j+1:0; //匹配成功,则多匹配一个字符
}
}
int KMP()
{
int len = strlen(p);
int j = 0;
for (int i = 0; s[i]; i ++) //正在匹配第i个字符
{
while (j && s[i] != p[j]) j = next[j];//匹配失败沿着匹配边走
if(s[i] == p[j]) j ++;
if (j == len) return 1;
}
return 0;
}
i