「这是我参与2022首次更文挑战的第19天,活动详情查看:2022首次更文挑战」。
KMP算法
问题:如何由当前部分匹配结果确定模式向右滑动的新比较起点 k?
若干问题描述
1. P[0] ~ P[k-1] = P[j-k] ~ P[j-1] 说明了什么?
a. k 与 j 具有函数关系,由当前失配位置 j ,可以计算出滑动位置 k
b. 滑动位置 k 仅与模式串 P 有关
2. P[0] ~ P[k-1] = P[j-k] ~ P[j-1] 的物理意义是什么?
前者为长度为 k 的前缀,后者为长度为k的后缀
3. P[0] ~ P[j]中前缀和后缀相等的真子串唯一吗?
4. 模式应该向右滑多远才能保证算法的正确性?
设next[j]表示在匹配过程中与P[j]比较不相等时,下标 j 的回溯位置
- j=0时, k=-1
- j=1时, k=0
- j=2时, P[0]≠P[1],因此,k = 0
- j=3时, P[0]=P[2],P[0]P[1] ≠P[1]P[2],因此,k = 1
- j=4时, P[0] ≠ P[3],P[0]P[1] = P[2]P[3],P[0]P[1]P[2]≠P[1]P[2]P[3],因此,k = 2
获取next函数值代码
void get_next(SString P, int next[]){
int i = 0;
int j = -1;
next[0] = -1;
while (i < P.length){
if (j == -1 || P.ch[i] == P.ch[j]){
i++; j++;
next[i] = j;
}else{
j = next[j];
}
}
算法思想
- 在串 T 和串 P 中分别设比较的起始下标 i 和 j;
- 循环直到 T 或 P 的所有字符均比较完: 如果T[i]等于P[j],继续比较 T 和 P 的下一个字符;否则,将 j 向移动到next[j]位置,即 j=next[j]; 如果 j=-1,则将 i 和 j 分别加 1,准备下一趟比较;
- 如果 P 中所有字符均比较完毕,则返回匹配的起始下标;否则返回 0;