zcmu 1550 (the smallest representation of a string)

Title link: https://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1550

Topic

Give you a string s, which can be moved to the left circularly, and the string lexicographical order is the smallest after at least a few left shifts.

Cycle left, for example s is (adac) then left shift can be adac, daca, acad, cada. The smallest lexicographic order here is acad, so it needs to be shifted left 3 times.

Ideas

O(n^2) will time out, here is an O(n) approach

i, j are two pointers, indicating the position of the first letter of the two strings. k represents the longest common prefix length of two strings. Since the two arrays need to be compared in lexicographic order, i and j cannot be the same, and i is initialized to 0, j is initialized to 1, and k is initialized to 0

When s[i+k] == s[j+k], the length of k as a common prefix is ​​increased by 1.

When s[i+k]> s[j+k], i will jump k+1 to reach the position of i+k+1

When s[i+k] <s[j+k], j will jump k+1 to reach the position of j+k+1, why?

What we should pay attention to is that, as a string with the smallest lexicographical order, there must be strings with the same length starting from s[i+1 to j-1] that are not less than those starting from s[i], otherwise i jumped to the back a long time ago, then if s[i+k]>s[j+k], then it indicates that the subscript starting from j has a smaller lexicographical order of length k.

Then i needs to be adjusted. Since the length of the string starting from j is k, then the k positions after i start do not need to run, because they will not be smaller than the current string starting from j, so i had to jump k+1 Positions. If s[i+k]<s[j+k], the same is true.

Then in order to ensure that i and j cannot be the same, we need to judge.If they are the same, we let j++, and finally the lexicographic order of the string of length n starting from i must be the smallest.

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;
}

Additional questions

Another similar question  P1368 [Template] Minimal Notation

The method can be said to be exactly the same, but it outputs the string with the smallest lexicographic order

#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;
}

 

Guess you like

Origin blog.csdn.net/weixin_43911947/article/details/112674690