题目描述
有时候程序员有很奇怪的方法来隐藏他们的口令。Binny会选择一个字符串S(由N个小写字母组成,5<=N<=5,000,000),然后他把S顺时针绕成一个圈,每次取一个做开头字母并顺时针依次取字母而组成一个字符串。这样将得到一些字符串,他把它们排序后取出第一个字符串。把这个字符串的第一个字母在原字符串中的位置-1做为口令。
如字符串alabala,按操作的到7个字符串,排序后得:
aalabal
abalaal
alaalab
alabala
balaala
laalaba
labalaa
第一个字符串为aalabal,这个a在原字符串位置为7,7-1=6,则6为口令。
输入输出格式
输入格式: 第一行:一个数:N
第二行开始:字符串:S(每72个字符一个换行符)
输出格式: 一行,为得到的口令
输入输出样例
输入样例
#1:
7
anabana
输出样例
#1:
6
说明题目满足:
30%的数据n<=10000
70%的数据n<=100000
100%的数据n<=5000000
时限 1s
正解,用两个指针指向头和头的下一个。如果头相同,就利用一个k继续向后比较,如果在某一位失配,直接将答案更不优的指针移到失配的下一位。(因为如果一个个继续移位比较的话,以失配前的点为头的串肯定不如k更优),然后继续比较,直到边界位置。
复杂度应该是O(N)。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=10000005;
char shu[maxn];
int main()
{
int n;
bool flag=0;
scanf("%d",&n);
for(int i=1;i<=n;i++) cin>>shu[i];
for(int i=n+1;i<=2*n;i++) shu[i]=shu[i-n];//现将数组复制一遍
int i=1,j=2,k=0;
while(i<=n&&j<=n)
{
k=0;
while(shu[i+k]==shu[j+k]&&k<n) k++;
if(k==n)
{
printf("%d",min(i,j)-1);
flag=1;
break;
}
if(shu[i+k]>shu[j+k]) i+=k+1;
else j+=k+1;
if(i==j) j++;
}
if(!flag) printf("%d\n",min(i,j)-1);
return 0;
}
错解:暴力匹配。洛谷上T一个点。先复制一下数组,然后开始逐位比较。比较到不同的,break掉
#include<iostream>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int maxn=10000005;
char shu[maxn],bj[maxn];
int main()
{
int l,jl=0;
scanf("%d",&l);
for(int i=1;i<=l;i++) cin>>shu[i];
for(int i=l+1;i<=2*l;i++) shu[i]=shu[i-l];
for(int i=1;i<=l;i++) bj[i]=shu[i];
for(int i=1;i<l;i++)
{
bool flag=0;
for(int j=1;j<=l;j++)
{
if(shu[j+i]<bj[j])
{
flag=1;
break;
}
if(shu[j+i]>bj[j]) break;
}
if(flag==1)
{
jl=i;
for(int j=1;j<=l;j++)
bj[j]=shu[j+i];
}
}
printf("%d\n",jl);
return 0;
}