Lyndon 分解
定义
首先我们介绍 Lyndon 分解的概念。
Lyndon 串:对于字符串 a,b,ab,aab,abb,ababb,abcd 都是 Lyndon 串。当且仅当 
Lyndon 分解:串 
Duval 算法
解释
Duval 可以在 
首先我们介绍另外一个概念:如果一个字符串 
Duval 算法运用了贪心的思想。算法过程中我们把串 
过程
整体描述一下,该算法每一次尝试将 
我们来更详细地解释一下算法的过程。定义一个指针 
- 如果 
 ,则将 添加到 末尾不会影响它的近似简单性。于是我们只需要让指针 自增(移向下一位)即可。 - 如果 
 ,那么 就变成了一个 Lyndon 串,于是我们将指针 自增,而让 指向 的首字符,这样 就变成了一个循环次数为 1 的新 Lyndon 串了。 - 如果 
 ,则 就不是一个近似简单串了,那么我们就要把 分解出它的一个 Lyndon 子串,这个 Lyndon 子串的长度将是 ,即它的一个循环节。然后把 变成分解完以后剩下的部分,继续循环下去(注意,这个情况下我们没有改变指针 ),直到循环节被截完。对于剩余部分,我们只需要将进度「回退」到剩余部分的开头即可。 
实现
下面的代码返回串 
=== "C++"
```cpp
// duval_algorithm
vector<string> duval(string const& s) {
  int n = s.size(), i = 0;
  vector<string> factorization;
  while (i < n) {
    int j = i + 1, k = i;
    while (j < n && s[k] <= s[j]) {
      if (s[k] < s[j])
        k = i;
      else
        k++;
      j++;
    }
    while (i <= k) {
      factorization.push_back(s.substr(i, j - k));
      i += j - k;
    }
  }
  return factorization;
}
```=== "Python"
```python
# duval_algorithm
def duval(s):
    n, i = len(s), 0
    factorization = []
    while i < n:
        j, k = i + 1, i
        while j < n and s[k] <= s[j]:
            if s[k] < s[j]:
                k = i
            else:
                k += 1
            j += 1
        while i <= k:
            factorization.append(s[i : i + j - k])
            i += j - k
    return factorization
```复杂度分析
接下来我们证明一下这个算法的复杂度。
外层的循环次数不超过 
最小表示法(Finding the smallest cyclic shift)
对于长度为 
我们构建串 
于是我们在分解的过程中记录每一次的近似 Lyndon 串的开头即可。
=== "C++"
```cpp
// smallest_cyclic_string
string min_cyclic_string(string s) {
  s += s;
  int n = s.size();
  int i = 0, ans = 0;
  while (i < n / 2) {
    ans = i;
    int j = i + 1, k = i;
    while (j < n && s[k] <= s[j]) {
      if (s[k] < s[j])
        k = i;
      else
        k++;
      j++;
    }
    while (i <= k) i += j - k;
  }
  return s.substr(ans, n / 2);
}
```=== "Python"
```python
# smallest_cyclic_string
def min_cyclic_string(s):
    s += s
    n = len(s)
    i, ans = 0, 0
    while i < n / 2:
        ans = i
        j, k = i + 1, i
        while j < n and s[k] <= s[j]:
            if s[k] < s[j]:
                k = i
            else:
                k += 1
            j += 1
        while i <= k:
            i += j - k
    return s[ans : ans + n / 2]
```习题
- 
本页面主要译自博文 Декомпозиция Линдона. Алгоритм Дюваля. Нахождение наименьшего циклического сдвига 与其英文翻译版 Lyndon factorization。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。
 
贡献者:@Menci@WenzelTian@Soresen@Jimmy@llh721113@Xiaodai@mgt@ksyx@Suyun514@Ir1dXD@hqztrue@orzAtalod@Xeonacid
本页面最近更新:2/3/2023, 12:00:00 AM,更新历史
发现错误?想一起完善? 在 GitHub 上编辑此页!
本页面的全部内容在 CC BY-SA 4.0 和 SATA 协议之条款下提供,附加条款亦可能应用