在首尾相连的字符串中,有一个最小(大)表示法的概念,意思就是在字符串旋转的过程中,有一种情况下字符串的字典序最小(大)。这里我们使用三指针的方法来寻找最小(大)的字典序串,首先破环成串,然后用i,j分别指定两个要比较的串的初始位置,k表示串比较的长度,若比较出两串的不同位置则将大的串的指针值前移,最终取i,j的最小值。
代码如下:
int getmin(string s,int len)//三指针搜索最小(大)序列
{
int i=0,j=1,k=0;
while(i<len&&j<len)
{
k=0;
while(s[i+k]==s[j+k]&&k<len)
k++;
if(s[i+k]<s[j+k])//求最大则是是s[i+k]>s[j+k]
j+=(k+1);
else
i+=(k+1);
//跳过已经比较的一段
if(i==j)//若出现i==j的情况则岔开一个继续比较
i++;
}
return min(i,j);//返回最小(大)字典序串的起点
}
下面给出一道题,利用map与最小表示法即可
题解:
#include "cstdio"
#include "string"
#include"iostream"
#include"algorithm"
#include"queue"
#include"stack"
#include"map"
#include"cmath"
using namespace std;
int getmin(string s,int len)//三指针搜索最小(大)序列
{
int i=0,j=1,k=0;
while(i<len&&j<len)
{
k=0;
while(s[i+k]==s[j+k]&&k<len)
k++;
if(s[i+k]<s[j+k])//求最大则是是s[i+k]>s[j+k]
j+=(k+1);
else
i+=(k+1);
//跳过已经比较的一段
if(i==j)//若出现i==j的情况则岔开一个继续比较
i++;
}
return min(i,j);//返回最小(大)字典序串的起点
}
//可旋转项链
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
int ans=0;
map<string,int>a;
while(n--)
{
string s;
cin>>s;
int len=s.length();
for(int i=0;i<len;i++)
s+=s[i];
//破环成串
int index=getmin(s,len);//得到最小字典序的字符串的起点
string ss=s.substr(index,len);
if(a[ss]==0)
{
ans++;
a[ss]=1;
}
}
cout<<ans<<endl;
}
return 0;
}