再次学习kmp
大学学数据结构的时候学的KMP,看了两个星期代码,就是有空就看看代码,琢磨琢磨明白了。没有看教材上的解析是因为那个解析太生涩了!
KMP的难点在于next数组的求解过程
next[i]存储的是什么,存储的next[0 ~ i-1]这个字符串后缀与前缀最大的相同长度(设为value_l)
这样当在 b[i]匹配失败的时候,转到下标value_l处继续匹配 //b[value_l] 和 b[i]不相同,但是它们前面长度value_l的字符串却相同。
如何快速求出next数组呢?
先初始化一下
next[0] = -1; //b[0]匹配失败的时候直接后移,重新开始。不为-1就是移动b,而不是调整b的位置
int i = 1; //要求解的next[i] 的 i
int j = 0; //这是一个游标,表示next[0,i-1]前后缀最大的公共长度
如果b[i] == b[j]
那么已经知道b[i]如果匹配失败转移到哪里去了,转移到next[j];因为最后一个字符相同导致现在是j+1个字符相同,转到j同样也会失败.
//所以说这句代码可以这么些 next[i] = next[j];
i和j 都皆大欢喜,携手往前一步 i++, j++; //公共长度+1 再接再厉求下一个结果
如果不相同呢
那么已经知道b[i]如果匹配失败转移到哪里去了,转移到下标j
//下次要计算next[i+1]的,它的最大前后缀公共长度j肯定需要调整的,我们就在这里收拾这个烂摊子
j, next[j], next[next[j]], next[next[next[j]]], …, 0 j这样依次往前跳,这些点的共同特征是什么
所有 有可能 和next[0~i]的后缀相同的前缀都在这里了!!! 说的是b[0, j]们
其实也不是都在这里,但是所有合适的前缀的都在这个列表里
即使有漏网之鱼,i和j协同前进的步伐肯定碾压过它们,但是它们为什么被忽略了呢?//说的就是 next[i] = next[j] 里面的 j 不会出现在这个枚举列表里
关键点就在于它们的最后一个字符必须要和b[i]对上,但是和它最后相同的但是更长的都在枚举列表里面,如果那个都没被选上,那么 这个j直接被忽略就太合理了
所以调整j的位置就是枚举呀
然后j都为求next[i+1]调整好了,i也就可以往前走一步了
记得在数据结构里面有代码形式更简洁妖艳的写法,我个人对那段代码是极度拜服。。 但是那段形式上最简化的代码(所有while跑的次数没有优化),并且却不便与这样理解。 贴网上的不保证正确