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

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


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

#include<stdio.h>
#include<string.h>
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(i<len&&j<len&&k<len)
    {
        int 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<j?i:j;//因为字典序大的位置被后移了,所以较小的位置就是答案
}
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,可以拿来练手哦~~

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