字符串最小表示法详解

问题描述

有一个字符串,这个字符串的首尾是连在一起的,要求寻找一个位置,以该位置为起点的字符串的字典序在所有的字符串中中最小。

算法

初始时,i=0,j=1,k=0。
首先,如果s[i]< s[j]那么很明显j++
如果s[i]>s[j]那么也很明显i=j++
剩下的就是当s[i]==s[j]时。
这时候有一个性质就是i和j之间的所有字符一定是大于等于s[i]的。
令k=0,i< j,循环寻找第一个s[i+k]!=s[j+k]的位置,如果s[i+k]< s[j+k]那么j+=k+1
首先s[i]到s[i+k-1]一定都是大于等于s[i],因为如果其中有一个数小于s[i],那么这个数一定在s[j]到s[j+k-1]中存在,又因为j的位置在i的前面,那么一定不会连续到k的位置,所以s[i]到s[i+k-1]一定不存在比s[i]小的字符。
所以j只能从j+k+1开始寻找。
如果s[i+k]>s[j+k],根据上面的分析s[i]到s[i+k-1]必然都是大于等于s[i]的,那么初始位置肯定不会在这之间,所以得从i+k+1开始找。

如果序列中某个数和s[i]相等的话,那么一定会有之前或者以后再这个位置起始过,所以不需要再从这个位置进行起始。

因为在这里i和j是等价的,i在前和j在前的结果是一样的,所以i和j的处理是相同的。

还有就是如果i==j那么让j++就可以回到原先的状态了

最后的时候,肯定是小的不会动,而大的会不停的向后移动,所以最后只需要输出i和j最小的一个即可

int getmin(char *s){
    int n=strlen(s);
    int i=0,j=1,k=0,t;
    while(i<n && j<n && k<n){
        t=s[(i+k)%n]-s[(j+k)%n];
        if (!t) k++;
        else{
            if (t>0) i+=k+1; 
            else j+=k+1;
            if (i==j) j++;
            k=0;
        }
    }
    return i<j?i:j;

猜你喜欢

转载自blog.csdn.net/qq_34921856/article/details/79904603
今日推荐