제목 링크 : https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1550
이야기
문자열 s를 주면 왼쪽으로 회전 할 수 있으며 문자열을 왼쪽으로 여러 번 이동 한 후 사전에 가장 적은 문자열이되도록 요청할 수 있습니다.
예를 들어 s가 (adac)이면 왼쪽으로 순환하면 adac, daca, acad, cada가 될 수 있습니다. 여기서 가장 작은 사전 식 순서는 acad이므로 왼쪽으로 3 번 이동해야합니다.
아이디어
O (n ^ 2) 시간이 초과됩니다. 여기에 O (n) 접근 방식이 있습니다.
i, j는 두 개의 포인터로 두 문자열의 첫 번째 문자의 위치를 나타냅니다. k는 두 문자열의 가장 긴 공통 접두사 길이를 나타냅니다. 두 배열을 사전 순서로 비교해야하므로 i와 j는 같을 수 없으며 i는 0으로 초기화되고 j는 1로 초기화되고 k는 0으로 초기화됩니다.
s [i + k] == s [j + k]이면 공통 접두사 인 k의 길이가 1 씩 증가합니다.
s [i + k]> s [j + k] 일 때 i + k + 1의 위치에 도달하기 위해 k + 1을 점프합니다.
s [i + k] <s [j + k] 일 때, j는 k + 1을 점프하여 j + k + 1의 위치에 도달합니다. 이유는 무엇입니까?
주의해야 할 점은 가장 작은 사전 순서를 가진 문자열로서 s [i]에서 시작하는 문자열보다 작지 않은 s [i + 1에서 j-1]로 시작하는 길이가 같은 문자열이 있어야한다는 것입니다. , 그렇지 않으면 i가 오래 전에 뒤로 건너 뛰고 s [i + k]> s [j + k]이면 j에서 시작하는 아래 첨자가 길이 k의 사전 순서가 더 작음을 나타냅니다.
그런 다음 i를 조정해야합니다 .j에서 시작하는 문자열의 길이가 k이므로 i가 시작된 이후의 k 위치는 실행할 필요가 없습니다. j에서 시작하는 현재 문자열보다 작지 않으므로 i k + 1 개의 위치를 점프해야했고 s [i + k] <s [j + k]이면 마찬가지입니다.
그런 다음 i와 j가 같을 수 없음을 확인하기 위해 우리는 판단 할 필요가 있습니다. 그들이 같으면 j ++로하고 마지막으로 i에서 시작하는 길이 n의 문자열의 사전 순서가 가장 작아야합니다.
ac 코드
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 3e5 + 5;
char s[maxn];
int cal(int n){
int i = 0, j = 1, k = 0;
while(i < n && j < n && k < n) {
int c1 = (i + k) % n, c2 = (j + k) % n;
if(s[c1] == s[c2]) k ++;
else {
if(s[c1] < s[c2]) j += k + 1;
else i += k + 1;
if(i == j) j ++;
k = 0;
}
}
return i;
}
int main(){
int t; scanf("%d",&t);
while(t --){
scanf("%s", s);
printf("%d\n", cal(strlen(s)));
}
return 0;
}
추가 질문
또 다른 유사한 질문 P1368 [템플릿] 최소 표기법
이 방법은 정확히 동일하다고 말할 수 있지만 가장 작은 사전 순서로 문자열을 출력합니다.
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 3e5 + 5;
int s[maxn];
int cal(int n){
int i = 0, j = 1, k = 0;
while(i < n && j < n && k < n){
int d1 = (i + k) % n, d2 = (j + k) % n;
if(s[d1] == s[d2]) k ++;
else{
if(s[d1] > s[d2]) i += k + 1;
else j += k + 1;
if(i == j) j ++;
k = 0;
}
}
return i;
}
int main(){
int n; scanf("%d",&n);
for(int i = 0; i < n; i ++) {
scanf("%d",&s[i]);
}
int ans = cal(n);
for(int i = 0; i < n; i ++) {
if(i) printf(" ");
printf("%d", s[(i + ans) % n]);
}
puts("");
return 0;
}