ZJU2006 Glass Beads - 字符串的最小表示

题目描述:

  有一串项链,项链的每个连接处的牢固程度不同,请你找出最容易断裂的地方。用一个字符串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

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值