三个变量
- i的含义是,第i个位置开始的字符串,
- j的含义是,第j个位置开始的字符串,
- k的含义是,从i个位置开始的字符串a,和从j个位置开始的字符串b,它们两个相同的长度。
思路
-
如果 s[(i+k)%len]>s[(j+k)%len] ,也就是在比较了相同的k位之后,字符串a和b不相同了。此时的a的字典序比较大,说明字符串的最小表示的开始位置不是i,但是 i~ i+k的字符串却和 j~j+k的字符串是相等的,所以我们把i的位置设置为 k+1 的位置,让i重新选取开始位置和字符串j比较。
-
如果,s[(i+k)%len]<s[(j+k)%len],说明字符串a小于字符串b,此时字符串b可以被舍弃,重新开始选取b,位置选取哪里?
我们选一个例子,13134,最开始i=0,j=1,k=0,第一步之后,j=2。因为只有s[(j+k)%len]>s[(i+k)%len]的时候,j才会增加。 -
所以当a串等于b串的时候,在此之前,a[i+1] ~ a[i+k]>a[i],而因为b==a,所以,b[j+1] ~ b[j+k] >b[0] (b[0]==a[0]) 。所以,我们选取位置的时候,没有必要考虑 j~j+k位置的字符,我们直接将j移到k+1的位置。
用例子做说明的话,字符串 13 和字符串13 ,此时比较下一位 1 和 4,因为ab的前几位均相同,我们没有必要再让j从下一位开始,一位一位和i=0开始的字符串去比较。
注意
代码里给了两组样例,这里需要说明的是,字符串的最小表示法表示的仅仅是,相对于传入字串,哪个位置开始为最小字串。
设最小表示位置为 k ,对于原字符串 s ,从 k 开始循环则 s 最小,但是对于 0<k<len_s-1 , 这样对于从k开始的substr中,字符串最小表示的位置需要重新查找。
比如 字符串 101010 最小表示位置是1,但是截开之后,字符串01010 ,它的最小表示位置在最后一位。
#include <iostream>
#include <stdio.h>
#include <string.h>
int getmin(char *s,int len)
{
int i=0,j=1,k=0;
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=i+k+1;
}
else {
j=j+k+1;
}
if (i==j) {
j++;
}
k=0;
}
}
return i<j?i:j;
}
int main()
{
char str[200];
scanf("%s",str);
int len=strlen(str);
printf("%d
",getmin(str,len));
return 0;
}
/*
2213211
101010
*/