题目描述:
有一串项链,项链的每个连接处的牢固程度不同,请你找出最容易断裂的地方。用一个字符串s来描述一个项链,串s是循环的,若s的某个循环s'是字典序中最小的,那么s'首字母在原串中的位置就是最容易断裂的地方。串s最多10000个字符。
分析:
最容易想到枚举串s的每个循环串,时间复杂度O(n^2),显然不行。
很显然可以对枚举法进行一些优化,最小串s'只可能是以串中最小的字母打头的。那么可以不用枚举那些较大的字母。像dabaa,则以d,b打头的串可以不用枚举。
但是在最坏的情况下(如aaaa)仍然会枚举所有的串。考虑baada,是否3个a开头的串都需要枚举呢?很容易知道,开头连续的a越多会越小。那么可以考虑找出所有以最长连续的最小字母打头的串,然后进行枚举。如abaabaad,只需枚举两个串即可。
我用这种方法AC了,程序不快,貌似许多人0.00秒就过了。应该有更好的方法,研究ing。。。
这种方法麻烦而慢,不推荐。
今天在网上找到一段代码叫"最小表示法"速度很快,感觉很像模式匹配算法。值得仔细研究一下~
可以参考一下这篇论文http://wurong81.spaces.live.com/blog/cns!5eb4a630986c6ecc!256.entry
#include<stdio.h>
#include<string.h>
int main()
{
char s[20003];
int i,j,n;
scanf("%d",&n);
getchar();
for(i=0;i<n;i++)
{
gets(s);
int a=0,b=1,k=0,m=strlen(s);
if(m==1)
{
printf("%d/n",1);
continue;
}
//将s复制一遍
for(j=m;j>=0;j--)
s[m+j]=s[j];
while(1)
{
//比较a,b开头的串
if(s[a+k]>s[b+k])
{
//当比较到长度为k时,b串胜出
//则a到a+k的串不用再比较
a=a+k+1;
if(a<=b)
a=b+1;
if(a>=m)
break;
k=0;
}
else if(s[a+k]<s[b+k])
{
b=b+k+1;
if(b<=a)
b=a+1;
if(b>=m)
break;
k=0;
}
else
{
//若a,b串第k个字符相等
k++;
if(k>=m)
{
break;
}
}
}
if(a>b)
printf("%d/n",b+1);
else
printf("%d/n",a+1);
}
return 0;
}
Sample Input
4
helloworld
amandamanda
dontcallmebfu
aaabaaa
Sample Output
10
11
6
5