Lyndon 分解
定义
首先我们介绍 Lyndon 分解的概念。
Lyndon 串:对于字符串 𝑠
,如果 𝑠
的字典序严格小于 𝑠
的所有后缀的字典序,我们称 𝑠
是简单串,或者 Lyndon 串。举一些例子,a
,b
,ab
,aab
,abb
,ababb
,abcd
都是 Lyndon 串。当且仅当 𝑠
的字典序严格小于它的所有非平凡的(非平凡:非空且不同于自身)循环同构串时,𝑠
才是 Lyndon 串。
Lyndon 分解:串 𝑠
的 Lyndon 分解记为 𝑠 =𝑤1𝑤2⋯𝑤𝑘
,其中所有 𝑤𝑖
为简单串,并且他们的字典序按照非严格单减排序,即 𝑤1 ≥𝑤2 ≥⋯ ≥𝑤𝑘
。可以发现,这样的分解存在且唯一。
Duval 算法
解释
Duval 可以在 𝑂(𝑛)
的时间内求出一个串的 Lyndon 分解。
首先我们介绍另外一个概念:如果一个字符串 𝑡
能够分解为 𝑡 =𝑤𝑤⋯――𝑤
的形式,其中 𝑤
是一个 Lyndon 串,而 ――𝑤
是 𝑤
的前缀(――𝑤
可能是空串),那么称 𝑡
是近似简单串(pre-simple),或者近似 Lyndon 串。一个 Lyndon 串也是近似 Lyndon 串。
Duval 算法运用了贪心的思想。算法过程中我们把串 𝑠
分成三个部分 𝑠 =𝑠1𝑠2𝑠3
,其中 𝑠1
是一个 Lyndon 串,它的 Lyndon 分解已经记录;𝑠2
是一个近似 Lyndon 串;𝑠3
是未处理的部分。
过程
整体描述一下,该算法每一次尝试将 𝑠3
的首字符添加到 𝑠2
的末尾。如果 𝑠2
不再是近似 Lyndon 串,那么我们就可以将 𝑠2
截出一部分前缀(即 Lyndon 分解)接在 𝑠1
末尾。
我们来更详细地解释一下算法的过程。定义一个指针 𝑖
指向 𝑠2
的首字符,则 𝑖
从 1
遍历到 𝑛
(字符串长度)。在循环的过程中我们定义另一个指针 𝑗
指向 𝑠3
的首字符,指针 𝑘
指向 𝑠2
中我们当前考虑的字符(意义是 𝑗
在 𝑠2
的上一个循环节中对应的字符)。我们的目标是将 𝑠[𝑗]
添加到 𝑠2
的末尾,这就需要将 𝑠[𝑗]
与 𝑠[𝑘]
做比较:
- 如果 𝑠[𝑗] =𝑠[𝑘]
,则将 𝑠[𝑗]
添加到 𝑠2
末尾不会影响它的近似简单性。于是我们只需要让指针 𝑗,𝑘
自增(移向下一位)即可。
- 如果 𝑠[𝑗] >𝑠[𝑘]
,那么 𝑠2𝑠[𝑗]
就变成了一个 Lyndon 串,于是我们将指针 𝑗
自增,而让 𝑘
指向 𝑠2
的首字符,这样 𝑠2
就变成了一个循环次数为 1 的新 Lyndon 串了。
- 如果 $s[j]
本页面最近更新:2024/2/15 22:17:29,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面贡献者:iamtwz, orzAtalod, sshwy, StudyingFather, ksyx, Xeonacid, Chrogeek, diauweb, Enter-tainer, gi-b716, hqztrue, Junyan721113, Menci, shawlleyw, Soresen, Suyun514
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用