字符串的最小表示法,就是對於一個字符串,能夠將它的最後一位放到第一位來,依次類推,一共有n種變形,n爲字符串長度算法
例如:ide
s="00ab"spa
變形有(省略引號)b00a ab00 0ab0指針
一共4種code
那麼找到其中字典序最小的一個,用的算法即是這個。blog
定義三個指針,i,j,k字符串
初始i=0;j=1;k=0get
首先,若是s[i]<s[j]那麼很明顯j++event
若是s[i]>s[j]那麼也很明顯i=j++class
省下的就是若是s[i]==s[j]的時候。
這時候有一個性質就是在i和j之間的全部的字符必定是大於等於s[i]的
另k=0,循環尋找第一個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]中存在,又由於一定有一個會在後面,因此若是s[j]先碰到了,那麼必定不會繼續到k的位置的,因此必定不存在比s[i]小的字符。
因此從其中的任意一個字符開始看成起始點,都不會比如今更小,因此只有從選出來的序列的後面那一個字符開始纔有可能會是最小。
因此j+=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; }