KMP总结
通俗描述
当在B中匹配A时,若在某一位失配,我们需要知道至少要将A往后移多少位才能确保之前匹配的内容仍然匹配(不然匹配肯定无效),而这个偏移量可以由“当前位置A的前缀中,A的非前缀后缀与A的前缀的最大匹配长度”计算出,考虑到在B中的计算过程实际上在计算“B的后缀与A的前缀的最大匹配长度”,两者可以用相似的做法求出,而非前缀性质可由初始化时的错位保证。
基本定义
- A:模板串,下标1~n
- B:文本串,下标1~m
- nxt[i] = max
- f[i] = max
- nxt[i]的“候选项”:
相关性质
引理1
若j是nxt[i]的候选项,则j-1必是nxt[i-1]的候选项。
引理2
若\(j_0\)是nxt[i]的一个候选项,则nxt[i]的小于\(j_0\)的最大的候选项是nxt[\(j_0\)]。
证:反证法,若有\(nxt[j_0] \le j_1 \le j_0\),\(j_1\)是nxt[i]的候选项。
\(\because j_1\)是nxt[i]的候选项
$ \therefore $ A[1~\(j_1\)] = A[i-\(j_1\)+1~i]
\(\because j_0\)是nxt[i]的候选项
$ \therefore $ A[1~\(j_0\)] = A[i-\(j_0\)+1~i],即A[\(j_0 - j_1 +1\) ~ \(j_0\)] = A[$ i-j_1+1$~ \(i\) ]
$ \therefore $ A[1 ~ \(j_1\)] = A[\(j_0-j_1+1\) ~ \(j_0\)]
$ \therefore $ nxt[\(j_0\)]应为\(j_1\)
$ \therefore $ 矛盾
即得证。
计算方法
由引理1和引理2,计算nxt[i]时,只要考虑nxt[i-1]+1,nxt[nxt[i-1]]+1,...亦可理解成“A错一位后匹配它自己”
nxt求法
nxt[1]=0;
for(int i=2,j=0;i<=n;i++)
{
while(j>0&&a[i]!=a[j+1]) j=nxt[j];
if(a[i]==a[j+1]) j++;
nxt[i]=j;
}
f求法
for(int i=1,j=0;i<=m;i++)
{
while(j&&(j==n||b[i]!=a[j+1])) j=nxt[j];
if(b[i]==a[j+1]) j++;
f[i]=j;
if(f[i]==n) { ... }
}
nxt数组的意义
- 自身定义:nxt[i] = max
- 可将整个KMP视为一个自动机,nxt数组即为“失配边”
常见用处
- 单文本单模板字符串匹配
- 求字符串最小循环元长度(如果有,即为n-nxt[n])
本作品由happyZYM采用知识共享 署名-非商业性使用-相同方式共享 4.0 (CC BY-NC-SA 4.0) 国际许可协议(镜像(简单版)镜像(完整版))进行许可。
转载请注明出处:https://www.cnblogs.com/happyZYM/p/11379686.html (近乎)全文转载而非引用的请在文首添加出处链接。