做了几道求循环节或者运用 next 数组的题,对于 next 数组理解更深了一些,然后开始正式去学习一下 kmp 算法
首先 总结一下 next 数组
next 数组 其实是对一个字符串自己进行检测扫描,对相应的重复部分进行一下标记,运用这个性质,我们可以用next 数组来判断字符串中是否存在某个循环节或者前缀是否在后边重复出现过,用途还是很多的,然后
回归正题, kmp 算法的目的是让我们更快的去对两个字符串进行匹配,还是先感谢大牛的博客
地址:https://www.cnblogs.com/yjiyjige/p/3263858.html
既然有了 next 数组了 那么匹配失败之后 我们就可以对其进行改进了
int kmp(char *p, char *t)
{
int i = 0; // 主串的位置
int j = 0; // 模式串的位置
getNext();
while (i < t.length && j < p.length) {
if (j == -1 || t[i] == p[j])
{
// 当j为-1时,移动i,j归0
i++;
j++;
}
else
{
// i = i - j + 1; 此处进行改变
j = next[j]; // j回到指定位置
}
}
if (j == p.length) //如果扫描到了头
{
return i - j;
}
else
{
return -1;
}
}
这样更改,我们在寻找 关键字符的算法就会更加简便,尤其是 i 不会回溯,这样就会很节省时间,
但是 这样的 kmp 还不是我们想要找的最终模式
有这样一个问题
当在这种情况是,我们的 j 前往 next [ j ]
但是之后就会发现
这一步是完全没有意义的。因为后面的B已经不匹配了,那前面的B也一定是不匹配的
显然,发生问题的原因在于P[j] == P[next[j]]。
那么做一个小改动
void getnext(char *c)
{
next[0] = -1;
int j = 0;
int k = -1;
while (j < p.length - 1) {
if (k == -1 || p[j] == p[k])
{
if (p[++j] == p[++k])
{ // 当两个字符相等时要跳过
next[j] = next[k];
}
else
{
next[j] = k;
}
}
else
{
k = next[k];
}
}
}
最终 整个 kmp 算法终于学习完了。。但是还只是粗略的了解了一下,熟练应用还需要多加练习
总结一下 kmp 的关键在于 对两个字符串比较时 定住一个 只移动另外一个,还有 next 数组的应用,用来记录已知字符串的相似情况, 记录的目的在于省去那些没必要的比较,进而加速比较速度