跳到主要内容

最小表示法

参考资料

简介

最小表示法(Minimum String Rotation)用于求字符串 ss 所有循环同构中字典序最小的那个的起始位置。

维护两个指针 i,ji,j(初始为 0,10,1)和公共前缀长度 kk:每次比较 s[(i+k)modn]s[(i+k)\bmod n]s[(j+k)modn]s[(j+k)\bmod n],相同则 kk 加一;若 s[(i+k)modn]>s[(j+k)modn]s[(i+k)\bmod n]>s[(j+k)\bmod n],则以 ii 为起点的后续 k+1k+1 个位置均非最优,直接跳过令 ii+k+1i\gets i+k+1,同理对称处理 jj。时间复杂度为 O(n)O(n)

实现

462 Bcpp
#include <bits/stdc++.h>
using namespace std;

int minimal(string s)
{
int n=s.size();
int i=0,j=1,k=0;
while(k<n&&i<n&&j<n)
{
if(s[(i+k)%n]==s[(j+k)%n])
{
k++;
}
else
{
s[(i+k)%n]>s[(j+k)%n]?i=i+k+1:j=j+k+1;
if(i==j)i++;
k=0;
}
}
return min(i,j);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
string s;
cin>>s;
int p=minimal(s);
int n=s.size();
for(int i=0;i<n;i++)cout<<s[(p+i)%n];
cout<<'\n';
return 0;
}

例题

若长度为 nn 的字符串 ss 中可以选择一个位置 ii,使得 sisns1si1=t\overline{s_i\cdots s_ns_1\cdots s_{i-1}}=t,则称 sstt 循环同构。字符串 ss最小表示 为与 ss 循环同构的所有字符串中字典序最小的字符串。

给定一个长度为 nn 的字符串 ss,请求出 ss 的最小表示。

给定一个长度为 nn 的序列,每次可将最左端元素移到最右端(循环移位)。求所有循环移位中字典序最小的序列。