问题:某字符串循环同构的所有字符串中,字典序最小的串是哪个?
1)什么是循环同构串?
例如 "a b c d f e" 字符串长度为 6, 那么就是说有 6 种循环同构的方法
"a b c d f e" , " b c d f e a " , "c d f e a b" , "d f e a b c" , " f e a b c d" , "e a b c d f"
暴力解法:将所有的串都列出,然后排序。
O(N) 解法 : 最小表示法
算法思想:
- 定义 i , j , k 三个指针 , i = 0, j = 1, k = 0 // i、j是两个“ 怀疑是最小的位置 “ k 的作用是s[ i ] == s[ j ] 时 向后比较 s[ i + k ] 和 s[ j + k ] 的大小。
- 如果 s [ i ] < s [ j ] 那么 // ++j , j指针向后移
- 如果 s [ i ] > s [ j ] 那么 // i = j ++ , i 指针指向 j 的位置, j 向后移动
- 如果 s [ i ] == s [ j ] 那么我们就需要移动 k 指针,找出 s [ i + k ] != s [ j + k ] 的位置,(肯定谁小要谁)// 首先s[i]到s[i+k-1]一定是大于等于s[i],因为如果其中有一个数小于s[i],那么这个数一定在s[j]到s[j+k-1]中存在,又因为必定有一个会在后面,所以如果s[j]先碰到了,那么一定不会继续到k的位置的,所以一定不存在比s[i]小的字符
- s [ i + k ] == s [ j + k ] 那么 ++k
- s [ i + k ] > s [ j + k ] 那么 i += k + 1, 并把 k 归为 0
- s [ i + k ] < s [ j + k] 那么 j += k + 1,并把 k 归为 0
- i == j 时,让 j 后移一位 ++j即可
最后(i 和 j)肯定是 小的不会动,而大的会不停向后移动,我们最后只用找出 i 和 j 中最小的那个即可。
模板:
string s;
int Get_Min(){
int i = 0, j = 1, k = 0;
int len = s.length();
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){ //s[(i + k)] < s[(j + k)]
j += k + 1;
k = 0;
} else { // s[(i + k)] > s[(j + k)]
i += k + 1;
k = 0;
}
if( i == j ) ++j;
}
return i < j ? i : j;
}