字符串匹配
- $w\sqsubset x$:w 为 x 前缀
- $w\sqsupset x$: w 为 x 后缀
- 后缀重叠引理:$x\sqsupset z,y\sqsupset z,|x|\leq|y|\Rightarrow x\sqsupset y$
- $P_k=P[1..k]$
朴素方法
$O((n-m+1)m)$
Rabin-Karp 算法
- 预处理 $O(m)$
- 编码,利用对素数取模,减少计算量
- 相等则逐字编码
- 最坏情况 $O((n-m+1)m)$
有限自动机
- 有限自动机 $M={Q,q_0,A,\Sigma,\delta}$
- 终态函数:$\phi:\Sigma^*\rightarrow Q$
- 后缀函数:$\sigma(x)=\max{k:P_k\sqsupset x}$
- 字符串匹配自动机
- $Q=\mathbb{Z}_m$, $q_0=0$, $A={m}$
- $\sigma(q,a)=\sigma(P_q a)$
- 不变量:$\phi(T_i)=\sigma(T_i)$
Knuth-Morris-Pratt Algorithm
- $\Theta(n+m)$
void kmp(char* pattern, char* text){
int j = 0;
for (int i=2;i<=n;++i){
while (j&&pattern[j+1]!=pattern[i]) j = nxt[j];
if (pattern[j+1]==pattern[i]) j++;
nxt[i] = j;
}
for (int i = 1, j = 0; i <= m; ++i){
while (j&&pattern[j+1]!=text[i]) j = nxt[j];
if (pattern[j+1]==text[i]) j++;
if (j==n) {
printf("%d\n", i-n+1);
j = nxt[j];
}
}
}