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数组的意义

  1. 自身定义:nxt[i] = max
  2. 可将整个KMP视为一个自动机,nxt数组即为“失配边”

常见用处

  1. 单文本单模板字符串匹配
  2. 求字符串最小循环元长度(如果有,即为n-nxt[n])
posted @ 2019-08-19 21:02  happyZYM  阅读(109)  评论(0编辑  收藏  举报