字符串 Runs 学习笔记
字符串 Runs 学习笔记
定义
对于字符串 \(S\),定义三元组 \((l,r,k)\) 是其一个 Run,当且仅当:
- \(k\) 是子串 \(S[l...r]\) 的最小周期。
- \(2k\le r-l+1\)。
- \([l,r]\) 是极大的。
Runs 的量级
\[\sum _{(l,r,k) \text { is a run}} \frac{r-l+1}d\le 3n-3
\]
这意味着 runs 的数量是 \(O(n)\) 的。
而且如果去掉 \(k\) 是最小周期的限制,此时合法的 \((l,r,k)\) 三元组仍然是 \(O(n)\) 的。如果求出最小周期 \(k\),那么 \(2k,3k,4k,\dots\) 也满足这些限制。
上述式子的证明见原论文。
求所有 Runs
如果知道了一个 run 的其中一个最小周期 \(S[l...r]\)(\(r-l+1=k\)),那么可以通过求出后缀 \(l\) 与后缀 \(r+1\) 的 LCP 求出这个 run 的右端点,对左端点同理求前缀 \(l-1\) 与前缀 \(r\) 的 LCS。当然还要检查是否满足 run 的条件。
我们称上面为一次检查。接下来有两种做法:
- 我们枚举周期长度 \(k\),每 \(k\) 个位置取一个关键点,若相邻两个关键点(\(x,y\))相等则检查区间 \([x,y-1]\)。显然任意一个周期为 \(k\) 的 run 都会包含至少两个关键点,于是这样可以找到所有 runs。
- 对于每个 run 考虑使后缀 \(l\) 字典序最小的周期 \([l,r]\),那么后缀 \(l+1,...,r\) 的字典序都比它大,又因为后缀 \(r+1\) 的字典序一定与其不等,假设比它小。于是可以对每个后缀找到后面第一个比它小的后缀然后检查一次,同理可以对每个后缀找到后面第一个比它大的后缀然后检查一次。
第一种方法需要检查调和级数的 \(O(n\log n)\) 次,因此需要配合上 SA 的 \(O(1)\) 求 LCP,才能做到总复杂度 \(O(n\log n)\)。
第二种方法需要检查最多 \(2n\) 次,因此可以使用字符串哈希代替 SA 做到 \(O(n\log n)\)。当然如果配合上 \(O(n)\) 求 SA 以及基数排序就可以做到 \(O(n)\) 求所有 runs。

浙公网安备 33010602011771号