【模板】字符串算法-字符串最小表示法

2014年10月,刚进hdu参加新生赛的时候,就遇到了字符串最小表示法的裸题,然而那时什么都不会的我只得写暴力,自然TLE了。之后在湖南师范大学第六届大学生计算机程序设计竞赛2B上,又做到了同样的裸题。


/*
字符串算法-字符串最小表示法模板
这是一个可以用O(n)时间解决"字符串呈环状,每一位置都可以作为首位,找出以哪个位置为开头,可以使得这个字符串的字典序最小(或最大)"问题的算法。
*/

#include
#include
const int M=5e6+10;
int casenum,casei;
int p;
char a[M];
int getmin(char s[])
{
    int i=0,j=1,k=0;//i和j是两个进行比较的起始匹配位点,k是匹配长度
    int len=strlen(s);
    while(iint t=s[(i+k)%len]-s[(j+k)%len];//比较两个串的大小关系
        if(t==0)k++;//如果相同,匹配长度增大,比较位置向移
        else //如果不同,则字典序大的位置肯定不会是答案,改变那个匹配位点
        {
            if(t>0)i+=k+1;
            else j+=k+1;
            if(i==j)j++;//i和j一定要错开
            k=0;//匹配长度要重置为0
        }
    }
    return i//因为字典序大的位置被后移了,所以较小的位置就是答案
}
int main()
{
    scanf("%d",&casenum);
    while(casenum--)
    {
        scanf("%s",a);
        p=getmin(a);
        printf("%d\n",p);
    }
}
/*
【题意】
字符串呈环状,每一位置都可以作为首位,以哪个位置为开头,可以使得这个字符串的字典序最小(或最大)?

【类型】
字符串算法-字符串最小表示法

【分析】
这个算法其实自己想也能想出来。
因为就算是自己设计的话,也应当是——
把这个字符串的0号位点与1号位点相比较,
如果一样,继续向后延伸比较,
如果不一样,肯定大的那个显然不会是答案,改变匹配串。

这里其实唯一需要理解的地方就是——
if(t>0)i+=k+1;
else j+=k+1;
为什么这里是变成k+1,中间的内容可以完全跳过呢?(比如t>0)
因为我们已经有{s[i]~s[i+k-1]==s[j]~s[j+k-1]了,且有s[i+k]>s[j+k],自然我们选i~i+k中的任意一点都是比j~j+k的相应位置要差的,所以自然可以都略过}

【时间复杂度&&优化】
i,j,k在某个位点都最多从0走到len,所以时间复杂度为O(n)

【trick】

【数据】
Sample Input
4
bcda 
aaa
a
adab

Sample Output
3
0
0
2
*/

ps:这套题虽然质量不高,还有两道错题2333,但是有三道裸题(2B字符串最小表示法、3C网络流和6F矩阵快速幂),对这些算法生疏的ACMer,可以拿来练手哦~~

你可能感兴趣的:(字符串算法-字符串最小表示法)