最小表示法的是求字符串s的字典序最小的循环同构,最大表示法是求字典序最大的循环同构。
循环同构是对于一个字符串,可从字符串串首选择字符,移动到串尾,或者从串尾,平移到串首。
以最小表示法为例:
对于一个字符串,设两个指针i,j,第一个指向s[0],第二个指向s[1],并且保证i,j绝对不相同。设一个k,对于s[(i+k)%len]与s[(j+k)%len]有以下三种情况:
1、s[(i+k)%len]==s[(j+k)%len]:
两个字符相同,说明两个字符都可能为循环同构的前缀,那么k++,比较下一个字符;
2、s[(i+k)%len]<s[(j+k)%len]:
i+k这个字符小于j+k说明j到j+k这一段一定不可能为循环同构的前缀,所以j+=k+1;
3、s[(i+k)%len]>s[(j+k)%len]:
与上一种情况相对;
代码:
#include <bits/stdc++.h>
using namespace std;
int n,ans,a[3000010];
int get_min()//最小表示法
{
int i=0,j=1,k=0;
//int len=strlen(s);
while(i<n&&j<n&&k<n)
{
if(a[(i+k)%n]==a[(j+k)%n])//相等比较下一个值
{
k++;
}
else
{
if(a[(i+k)%n]<a[(j+k)%n])//i+k小于j+k则说明j到j+k都不可能是字符串的前缀
{
j+=k+1;
}
else//反之i到i+k都不可能是字符串的前缀
{
i+=k+1;
}
if(i==j)
j++;
k=0;
}
}
return min(i,j);//返回i与j中小的那个
}
int get_max()
{
int i=0,j=1,k=0;
while(i<n&&j<n&&k<n)
{
if(a[(i+k)%n]==a[(j+k)%n])//相等比较下一个值
{
k++;
}
else
{
if(a[(i+k)%n]<a[(j+k)%n])//i+k小于j+k则说明i到i+k都不可能是字符串的前缀
{
i+=k+1;
}
else//反之j到j+k都不可能是字符串的前缀
{
j+=k+1;
}
if(i==j)
j++;
k=0;
}
}
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
ans=get_min();
for(int i=0;i<n;i++)
printf("%d ",a[(i+ans)%n]);
return 0;
}