Titellink: https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1550
Thema
Geben Sie eine Zeichenfolge s, sie kann sich nach links drehen, und bitten Sie die Zeichenfolge, die lexikografisch am wenigsten lexikografisch zu sein, nachdem Sie sie mehrmals nach links verschoben haben.
Zyklus links, zum Beispiel s ist (adac), dann kann die Linksverschiebung adac, daca, acad, cada sein. Die kleinste lexikografische Reihenfolge ist hier acad, daher muss sie dreimal nach links verschoben werden.
Ideen
O (n ^ 2) tritt eine Zeitüberschreitung auf, hier ist ein O (n) -Ansatz
i, j sind zwei Zeiger, die die Position des ersten Buchstabens der beiden Zeichenfolgen angeben. k stellt die längste gemeinsame Präfixlänge von zwei Zeichenfolgen dar. Da die beiden Arrays in lexikografischer Reihenfolge verglichen werden müssen, können i und j nicht gleich sein, und i wird auf 0 initialisiert, j wird auf 1 initialisiert und k wird auf 0 initialisiert
Wenn s [i + k] == s [j + k] ist, wird die Länge von k als gemeinsames Präfix um 1 erhöht.
Wenn s [i + k]> s [j + k] ist, springe ich k + 1, um die Position von i + k + 1 zu erreichen
Wenn s [i + k] <s [j + k] ist, springt j k + 1, um die Position von j + k + 1 zu erreichen. Warum?
Was wir beachten sollten, ist, dass es als Zeichenfolge mit der kleinsten lexikografischen Reihenfolge Zeichenfolgen mit derselben Länge geben muss, die von s [i + 1 bis j-1] beginnen und nicht kleiner sind als diejenigen, die von s [i] beginnen. , sonst bin ich vor langer Zeit nach hinten gesprungen, wenn s [i + k]> s [j + k], dann zeigt es an, dass der Index ab j eine kleinere lexikographische Reihenfolge der Länge k hat
Dann muss ich angepasst werden. Da die Länge der Zeichenfolge ab j k ist, müssen die k-Positionen nach dem Start von i nicht ausgeführt werden, da sie nicht kleiner sind als die aktuelle Zeichenfolge ab j, also i musste k + 1 Positionen springen. Wenn s [i + k] <s [j + k] ist, gilt das Gleiche.
Um sicherzustellen, dass i und j nicht gleich sein können, müssen wir beurteilen. Wenn sie gleich sind, lassen wir j ++, und schließlich muss die lexikografische Reihenfolge der Zeichenfolge der Länge n ab i die kleinste sein.
AC-Code
#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;
}
Weitere Fragen
Eine andere ähnliche Frage P1368 [Vorlage] Minimale Notation
Man kann sagen, dass die Methode genau dieselbe ist, aber sie gibt die Zeichenfolge mit der kleinsten lexikografischen Reihenfolge aus
#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;
}