第一次遇到最小表示法,本来是吧所有的情况遍历了一下,结果超时了,看完题解发现是最小表示法,很经典。
【最小表示法】
先给代码,如果看懂了,就不用看下面的解释了。
最小表示法不仅可以求解字典序最小的,还可以求解字典序最大的。
int i = 0, j = 1, k = 0, t;
while(i < l && j < l && k < l)
{
int a=(i+k)%l;
int b=(j+k)%l;
t =str[a] - str[b];
if(!t) k++;
else
{
if(t > 0) i = i + k + 1;
else j = j + k + 1;
if(i == j) ++ j;
k = 0;
}
}
if(i>j) i=j;
++i;
例如:str=“SKYLONG”字符串;
向右移动
SKYLONG 1
KYLONGS 2
YLONGSK 3
LONGSKY 4
ONGSKYL 5
NGSKYLO 6
GSKYLON 7
有7种情况,让你求出字典序最小的序列,用最小表示法,就最简单了。
两个字符串比较,如果开头有小的字符,那么那个字符串的字典序就一定是最小的,所以就可以将相同的跳过去,先有这个思想。
i代表的就是字符串的开头,j代表的就是与之相比的字符串的开头。
k代表两字符串匹配的长度。
int a=(i+k)%l;//避免i和ja超出l的范围,毕竟要遍历所有的情况
int b=(j+k)%l;
t =str[a] - str[b];//t的值代表str[a]和str[b]的大小。
if(!t) k++;//如果相等就比较下一个,毕竟k代表他们比较的长度。
else
{
//因为我们要找字典序最小的
//t>0是代表i代示的字符串较大,就找下一个字符串进行比较
//t<0是代表j代示的字符串较大,就找下一个字符串进行比较
if(t > 0) i = i + k + 1;
else j = j + k + 1;
if(i == j) ++ j;//如果i和j相等了,就将他俩错位一下,因为i一直代表的就是字典序最小的那个串,所以让j加一。
k = 0;//然后让k为0,从头比较。
}
//跳出循环后
if(i>j) i=j;//在执行这一步时if(t > 0) i = i + k + 1;说明j的字符串是字典序最小的。
//如果发现已经跳出了循环,就可能造成j的是最小的,所以将i=j;
i++;
如果理解了最小表示法求解字典序最小的,那么你就可以写出用最小表示法求解字典序最大的。
下面是这道题的代码:
题目链接:传送门
思路: 不管是字典序最小还是字典序最大,他们的个数是一样的,用kmp来求解他们的个数。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
const int maxn=1e6+9;
char str[maxn];
int nex[maxn];
void get_next(int n)
{
int i=0,j=-1;
nex[0]=-1;
while(i<n)
{
if(j==-1||str[i]==str[j])
{
i++,j++;
nex[i]=j;
}
else j=nex[j];
}
}
int main()
{
while(~scanf("%s",str))
{
memset(nex,0,sizeof(nex));
int l=strlen(str);
int i = 0, j = 1, k = 0, t;
while(i < l && j < l && k < l)//找字典序最小的串的开头
{
int a=(i+k)%l;
int b=(j+k)%l;
t =str[a] - str[b];
if(!t) k++;
else
{
if(t > 0) i = i + k + 1;
else j = j + k + 1;
if(i == j) ++ j;
k = 0;
}
}
if(i>j) i=j;
int min_=++i;
i = 0, j = 1, k = 0, t;
while(i < l && j < l && k < l)//找字典序最大的串的开头
{
int a=(i+k)%l;
int b=(j+k)%l;
t =str[a] - str[b];
if(!t) k++;
else
{
if(t <0) i = i + k + 1;
else j = j + k + 1;
if(i==j) ++ j;
k = 0;
}
}
if(i>j) i=j;
int max_=++i;
get_next(l);//kmp
int h=l-nex[l];
int jj=l/h;
printf("%d %d %d %d\n",min_,jj,max_,jj);
}
return 0;
}