紫薯P52 例题3-6
一、题意
有kase个循环字符串,输出每个字符串 (长度n<=100) 的最小表示。
二、解析
经典的求最小循环字符串题目,这里用来复习一下它的一种O(1)算法。
基本思想是双指针i, j,用k表示从i、j开始的子串的当前比对到的完全一样的长度,当判断出i、j的某一条子串的i+k、j+k位置有所不同时,大的那一条(比如是j)就可以往后跳k+1个字符,因为以这些字符起始的循环字符串已经不可能是最小的(比它们小的在i开始的串的子串中)。用这样的方法当i、j串中的某一个超过n时就不用再判断了(因为n个可能的起始位置都判断过了)。此时剩余的那个串就是最小的循环字符串。
三、代码
#include <iostream>
#include <string>
#include <cmath>
using namespace std;
int kase, n;
string str;
int solve() {
int i = 0, j = 1, k = 0;
while(i < n && j < n) {
int tmp = str[(i + k) % n] - str[(j + k) % n];
if(tmp == 0) k ++;
else if(tmp < 0) j += k + 1, k = 0;
else i += k + 1, k = 0;
if(i == j) j ++, k = 0;
}
return min(i, j);
}
int main() {
cin >> kase;
while(kase --) {
cin >> str;
n = str.size();
int idx = solve();
cout << str.substr(idx) + str.substr(0, idx) << endl;
}
}
/*
2
CGAGTCAGCT
CTCC
*/四、归纳
- 经典算法可以记一下:O(1)时间求最小循环字符串。
差点写不出来...

京公网安备 11010502036488号