字符串的最小表示法

三个变量

  • i的含义是,第i个位置开始的字符串,
  • j的含义是,第j个位置开始的字符串,
  • k的含义是,从i个位置开始的字符串a,和从j个位置开始的字符串b,它们两个相同的长度。

思路

  1. 如果 s[(i+k)%len]>s[(j+k)%len] ,也就是在比较了相同的k位之后,字符串a和b不相同了。此时的a的字典序比较大,说明字符串的最小表示的开始位置不是i,但是 i~ i+k的字符串却和 j~j+k的字符串是相等的,所以我们把i的位置设置为 k+1 的位置,让i重新选取开始位置和字符串j比较。

  2. 如果,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才会增加。

  3. 所以当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
*/

原文地址:https://www.cnblogs.com/xyqxyq/p/12328889.html