您的位置:首页 > 其它

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

2015-12-04 08:14 323 查看
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,可以拿来练手哦~~
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: