这里会显示出您选择的修订版和当前版本之间的差别。
| 两侧同时换到之前的修订记录 前一修订版 后一修订版 | 前一修订版 | ||
|
2020-2021:teams:legal_string:后缀数组_lgwza [2020/07/24 16:10] lgwza [$O(n)$ 做法] |
2020-2021:teams:legal_string:后缀数组_lgwza [2020/07/24 16:17] (当前版本) lgwza [一些常数优化] |
||
|---|---|---|---|
| 行 43: | 行 43: | ||
| 参考代码: | 参考代码: | ||
| + | <hidden> | ||
| <code cpp> | <code cpp> | ||
| #include <algorithm> | #include <algorithm> | ||
| 行 86: | 行 87: | ||
| } | } | ||
| </code> | </code> | ||
| + | </hidden> | ||
| ==== $O(n\log n)$ 做法 ==== | ==== $O(n\log n)$ 做法 ==== | ||
| 行 97: | 行 98: | ||
| 参考代码: | 参考代码: | ||
| + | <hidden> | ||
| <code cpp> | <code cpp> | ||
| #include <algorithm> | #include <algorithm> | ||
| 行 147: | 行 149: | ||
| } | } | ||
| </code> | </code> | ||
| + | </hidden> | ||
| ==== 一些常数优化 ==== | ==== 一些常数优化 ==== | ||
| 行 158: | 行 161: | ||
| 实际上,像这样就可以了: | 实际上,像这样就可以了: | ||
| + | |||
| <code cpp> | <code cpp> | ||
| 行 183: | 行 187: | ||
| 参考代码: | 参考代码: | ||
| + | <hidden> | ||
| <code cpp> | <code cpp> | ||
| #include <algorithm> | #include <algorithm> | ||
| 行 228: | 行 233: | ||
| } | } | ||
| </code> | </code> | ||
| + | </hidden> | ||
| ==== $O(n)$ 做法 ==== | ==== $O(n)$ 做法 ==== | ||
| 行 267: | 行 273: | ||
| 参考代码: | 参考代码: | ||
| + | <hidden> | ||
| <code cpp> | <code cpp> | ||
| #include <cctype> | #include <cctype> | ||
| 行 322: | 行 329: | ||
| } | } | ||
| </code> | </code> | ||
| + | </hidden> | ||
| + | |||
| + | ===== height 数组 ===== | ||
| + | |||
| + | ==== LCP(最长公共前缀) ==== | ||
| + | |||
| + | 两个字符串 $S$ 和 $T$ 的 LCP 就是最大的 $x$ ($x\le\min(|S|,|T|)$) 使得 $S_i=T_i(\forall1\le i\le x)$。 | ||
| + | |||
| + | 下文中以 $lcp(i,j)$ 表示后缀 $i$ 和后缀 $j$ 的最长公共前缀(的长度)。 | ||
| + | |||
| + | ==== height 数组的定义 ==== | ||
| + | |||
| + | $height[i]=lcp(sa[i],sa[i-1])$,即第 $i$ 名的后缀与它前一名的后缀的最长公共前缀。 | ||
| + | |||
| + | $height[1]$ 可以视作 $0$。 | ||
| + | |||
| + | ==== O(n) 求 height 数组需要的一个引理 ==== | ||
| + | |||
| + | $height[rk[i]]\ge height[rk[i-1]]-1$ | ||
| + | |||
| + | 证明: | ||
| + | |||
| + | 略 | ||
| + | |||
| + | ==== O(n) 求 height 数组的代码实现 ==== | ||
| + | |||
| + | 利用上面这个引理暴力求即可: | ||
| + | |||
| + | <code cpp> | ||
| + | for (i = 1, k = 0; i <= n; ++i) { | ||
| + | if (k) --k; | ||
| + | while (s[i + k] == s[sa[rk[i] - 1] + k]) ++k; | ||
| + | ht[rk[i]] = k; // height太长了缩写为ht | ||
| + | } | ||
| + | </code> | ||
| + | $k$ 不会超过 $n$,最多减 $n$ 次,所以最多加 $2n$ 次,总复杂度就是 $O(n)$。 | ||
| + | |||
| + | 未完待续 | ||
| + | |||
| + | ===== 参考链接 ===== | ||
| + | |||
| + | [[https://oi-wiki.org/string/sa/|参考链接]] | ||