力扣网参考代码
int* buildNext(char* P) { // 构造模式串 P 的 next 表
size_t m = strlen(P), j = 0; // “主”串指针
int* N = new int[m]; // next 表
int t = N[0] = -1; // 模式串指针
while (j < m - 1)
if ( 0 > t || P[j] == P[t]){ // 匹配
j++; t++;
N[j] = t; // 此句可改进为 N[j] = (P[j] != P[t] ? t : N[t]);
}else // 失配
t = N[t];
return N;
}
代码来源:力扣学习页面下的《数组和字符串》,字符串简介章节的选修KMP
代码理解
以理解t的更新方式来理解代码中的while循环(为了方便表示,j指针移动到第n位的时候,说成第n次循环,实际上进入第一次循环时,j=0):
第一步,给N的第一项赋值-1(按代码第一次进入循环的执行方式,模式串长度允许的话,N的第二项也固定为0)
第二步,循环n-1次后的第n次循环,假设前面几次循环都满足if中的条件,即j和t对应的位置的字符有几位是相等的,那么可以抽象的表示为:
此时,P[t]和P[j]不相等,接下来给t赋值为N[t]是最难理解的一步,先来看看N[t]是什么:
由next表的定义,可以得到图中的结论①;再由这一步分析的前置条件(前面加粗的部分),可以得到图中的结论②
此时,t = N[t] 的结果就应该是,t指向下图中这个位置(由next表定义可知,橙色表示部分的子串相等):
给t赋值之后,再进入 while 循环内,此时的 if 语句就是判断 ” * * * ” 后面的 字符与 j指向的字符是否相等,若是不相等,再重复前面的这种操作;若是相等,则可以直接把相等数量加1,可以加的原因是:“XX”前面的子串与“YY”前面的 “ * * * +++” 子串是相等的,而这子串中,“ ** ” 与 “ ++ ”又是相等的,所以最开头的 “ ** ” 和 “ YY ” 前面的 “ ++ ” 是相等的。