Lyndon 串:对于字符串 s,如果 s 的字典序严格小于 s 的所有后缀的字典序,我们称 s 是简单串,或者 Lyndon 串。举一些例子,a,b,ab,aab,abb,ababb,abcd 都是 Lyndon 串。当且仅当 s 的字典序严格小于它的所有非平凡的(非平凡:非空且不同于自身)循环同构串时,s 才是 Lyndon 串。
// C++ Version// duval_algorithmvector<string>duval(stringconst&s){intn=s.size(),i=0;vector<string>factorization;while(i<n){intj=i+1,k=i;while(j<n&&s[k]<=s[j]){if(s[k]<s[j])k=i;elsek++;j++;}while(i<=k){factorization.push_back(s.substr(i,j-k));i+=j-k;}}returnfactorization;}
我们构建串 ss 的 Lyndon 分解,然后寻找这个分解中的一个 Lyndon 串 t,使得它的起点小于 n 且终点大于等于 n。可以很容易地使用 Lyndon 分解的性质证明,子串 t 的首字符就是 s 的最小表示法的首字符,即我们沿着 t 的开头往后 n 个字符组成的串就是 s 的最小表示法。
于是我们在分解的过程中记录每一次的近似 Lyndon 串的开头即可。
1 2 3 4 5 6 7 8 91011121314151617181920
// C++ Version// smallest_cyclic_stringstringmin_cyclic_string(strings){s+=s;intn=s.size();inti=0,ans=0;while(i<n/2){ans=i;intj=i+1,k=i;while(j<n&&s[k]<=s[j]){if(s[k]<s[j])k=i;elsek++;j++;}while(i<=k)i+=j-k;}returns.substr(ans,n/2);}