用最小表示法返回最小表示串(字典序最小的同构串)第一个字符在原始串中的下标。
提交: 161 解决: 45
[ 提交][ 状态][ 讨论版]
用两个指针i,j,i初始化为0,j初始化为1,用k表示当前已经匹配串的长度。如果str[i+k]==str[j+k],j++,否则如果str[i+k]>str[j+k],说明以i开始的同构串肯定不是最小的,并且以i开始的到以i+k开始的都不会是最小的,因为若以i+x开头,0<=x<=k,那么这时以j+x开头的串比这个串小,因为前面相等,比较到i+k和j+k发现str[j+k]小,因此就把i移到i+k+1。同理如果str[i+k]>str[j+k],把j移到j+k+1,如果i==j,j++。直到i,j,k中有一个大于等于串的长度为止。最后返回i和j里较小的那个。
int min_express(char* str){
int len=strlen(str),i=0,j=1,k=0;
while(i<len&&j<len&&k<len){
int t=str[(j+k)%len]-str[(i+k)%len];
if(!t) k++;
else{
if(t<0) i=i+k+1;
else j=j+k+1;
if(j==i) j++;
k=0;
}
}
return min(i,j);
}
问题 C: 最强阵容点击打开链接
时间限制: 1 Sec 内存限制: 128 MB提交: 161 解决: 45
[ 提交][ 状态][ 讨论版]
题目描述
拿着新换来的英雄卡,小李满心欢喜的准备和同学们PK一下。
他们的游戏规则非常简单,双方把自己的牌绕成一圈,然后指定一个起点,从该张牌开始顺时针方向往后取,谁取出的字符串字典序更小(从左到右开始比较,碰到第一个不一样的字符进行比较,比较规则为a<b<…<z)谁将获得胜利。具体规则可参考样例。虽然现在小李的牌已经很好了,但是你能不能帮他快速算出起始位置,使得他能够派出最强阵容。
他们的游戏规则非常简单,双方把自己的牌绕成一圈,然后指定一个起点,从该张牌开始顺时针方向往后取,谁取出的字符串字典序更小(从左到右开始比较,碰到第一个不一样的字符进行比较,比较规则为a<b<…<z)谁将获得胜利。具体规则可参考样例。虽然现在小李的牌已经很好了,但是你能不能帮他快速算出起始位置,使得他能够派出最强阵容。
输入
第一行n(1<=n<=30000),表示共有n张牌。
第二行共n个用一个空格隔开的小写字母,表示给定的一圈牌起始序列。
第二行共n个用一个空格隔开的小写字母,表示给定的一圈牌起始序列。
输出
仅一个整数,能获得最小字典序字符串的起点位置。如果有多个位置开始的字符串一样,则输出最小的那个位置,且第一个位置从1开始。
样例输入
4
b c a b
样例输出
3
提示
四个位置取出的字符串分别为bcab,cabb,abbc,bbca,显然最小位置是3。
#include <stdio.h>
#include <string.h>
int n;
char a[600005];
int main()
{
int i,j,mii,k;
scanf("%d\n",&n); // 按照题目格式严格输入 (回车)
for(i=0;i<n-1;i++)
{
scanf("%c",&a[i]);
getchar();
}
scanf("%c",&a[n-1]); //最后一个字符后无空格
i=0;j=1;k=0;
while(i<n&&j<n&&k<n)
{
int t=a[(i+k)%n]-a[(j+k)%n];
if(!t)
k++;
else
{
if(t<0)
j=j+k+1;
else
i=i+k+1;
if(i==j)
j++;
k=0;
}
}
mii=i<j?i:j;
printf("%d\n",mii+1);
return 0;
}