前缀函数 $\pi[i]$
定义
最长相等 真前缀 & 真后缀 の 长度 $$ \pi[i] = \max_{k=0…i}{{k: s[0 … k] = s[i - k + 1 … i]}} $$
对于字符串 abcabcd
的前缀函数 $\pi[i]$ :
$i$ | $\pi[i]$ | 子串 | 相等前后缀 |
---|---|---|---|
0 | 0 | a |
null |
1 | 0 | ab |
null |
2 | 0 | abc |
null |
3 | 1 | abca |
a |
4 | 2 | abcab |
ab |
5 | 3 | abcabc |
abc |
6 | 0 | abcabcd |
null |
实现
朴素实现
暴力模拟匹配,从大到小,匹配到就返回
|
|
得配优化
观察到:$\pi[i + 1] - \pi[i] \le 1$
|
|
失配优化
在 $\pi[i] = \pi[i - 1] + 1$ 失配后,假定 $\pi[i] = j + 1$ 得配,则有:
$$ \begin{cases} str[j] = str[i] \ str[0 … j - 1] = str[i - j … i - 1] = str[\pi[i] - j + 1, \pi[i] - 1] \end{cases} $$ 第二条比较关键,即 $j$ 在 $str[0 … i]$ 是真前后缀匹配的,$\pi[i]$ 也是在 $str[0 … i]$ 真前后缀匹配的 $\Rightarrow$ $j$ 在 $str[0 … \pi[i] - 1]$ 是前后缀匹配的
于是有递推公式:
$$ j^{(n)} = \pi[j^{(n - 1)} - 1] $$
:star:最终实现:
|
|
时间复杂度 $O(n)$ ,在线算法。
KMP
适用:字符串 $s$,文本 $t$ . 求 $s$ 在 $t$ 出现的所有位置 (occurrence)
实现
构造一个字符串 $str = s+#+t$,其中 $#$ 是一个同时不存在于 $s$ 和 $t$ 的字符.
记 $\pi[i]$ 是 $str$ 的前缀函数. 因为存在 $#$ ,所以 $\forall i, \pi[i] \le \left| s \right|$ .
所以 $s = t[i .. i + \left| s \right| - 1] \Leftrightarrow \pi[i + 2 * \left| s \right|] = \left| s \right|$ .
|
|
- TODO: 因为字符串在 oi 中不算热点内容,所以暂时先更到 kmp 🔽