最小表示法-解決O(n)找循環字符串最小字典序串

https://ac.nowcoder.com/acm/contest/328/A

 

分爲三種情況1.如果str[i+k]==str[j+k] k++。

2.如果str[i+k] > str[j+k] i = i + k + 1,即最小表示不可能以str[i->i+k]開頭。

3.如果str[i+k] < str[j+k] j = j + k + 1,即最小表示不可能以str[j->j+k]開頭。

那麼只要循環n次,就能夠判斷出字符串的最小表示是以哪個字符開頭。

爲什麼當str[i+k] > str[j+k] i = i + k + 1,最小表示不可能以str[i->i+k]開頭,

讓我們來舉個栗子。當i=1,j=5,k=3時,str[i+k] > str[j+k]。

首先有S1S2S3 == S5S6S7,S4 > S8。那麼以字符S2開頭肯定不如以字符S6開頭更優,因爲S4 > S8啊。

#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;

char s[N], mn[N];

int getMin(){
    int i=0, j=1, k=0;
    int len=strlen(s);
    
    while(i<len && j<len && k<len){
        int ti=(i+k)%len, tj=(j+k)%len;
        if(s[ti]==s[tj]) k++;
        else{
            if(s[ti]>s[tj]){
                i=i+k+1;
                k=0;
            }
            else{
                j=j+k+1;
                k=0;
            }
            if(i==j) j++;
        }
    }
    return i<j?i:j;
}

int main(){
    int n;
    scanf("%d", &n);
    scanf("%s", s);
    
    int k=getMin();
    
    for(int i=0; i<n; i++){
        mn[i]=s[(i+k)%n];
    }
    mn[n]=0;
    if(strcmp(s, mn)==0) 
        printf("NO\n");
    else
        printf("YES\n");
    
    return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章