zcmu 1550(文字列の最小表現)

タイトルリンク: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は2つのポインタであり、2つの文字列の最初の文字の位置を示します。kは、2つの文字列の最長の共通プレフィックス長を表します。2つの配列は辞書式順序で比較する必要があるため、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ジャンプして、i + k +1の位置に到達します。

s [i + k] <s [j + k]の場合、jはk +1をジャンプしてj + k + 1の位置に到達します。なぜですか?

注意すべき点は、辞書式順序が最小の文字列として、s [i + 1からj-1]で始まる同じ長さで、s [i]で始まる文字列以上でなければならないということです。 、それ以外の場合、iはずっと前に後ろにジャンプし、s [i + k]> s [j + k]の場合、jで始まる添え字の辞書式順序が小さいことを示します。

次に、iを調整する必要があります.jから始まる文字列の長さがkであるため、iの開始後のkの位置は、jから始まる現在の文字列よりも小さくならないため、実行する必要はありません。 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;
}

 

おすすめ

転載: blog.csdn.net/weixin_43911947/article/details/112674690