計蒜客 - 重複的密文

計蒜客 - 重複的密文

蒜頭君收到了一串密文,但是由於接收器壞了,他不停的重複接收,終於,蒜頭君把插頭拔了,機器停止了,但是蒜頭君已經收到了一個很長字符串,它是由某個原始串不停的重複形成了,因爲斷電,最後一遍也不一定是完整的。蒜頭君現在想知道這個原始串的最短可能長度是多少。

輸入格式

第一行輸入一個正整數 L(1<L106)L(1 < L \leq 10^6),表示這個字符串的長度。

第二行輸入一個字符串,全部由小寫字母組成。

8
cabcabca

輸出格式

答案輸出,輸出最短的可能長度。

3

這道題是求 KMP 的最小循環節。

仔細觀察 next[] 數組,可以發現,如果出現循環,那麼除了第一個循環節的值都是 00,從第二個循環節開始,包括最後一個,都是遞增的,而且記錄了最長公共前綴。

所以利用 KMP 求出 next[] 數組,L - next[L] 就是答案。

注:next[] 數組也常被稱作 fail[] 數組,失敗鏈接值。

#include <bits/stdc++.h>

// 爲了編程方便,next 數組下標從 1 開始,所以 string 也要下標從 1 開始,所以封裝了一個 read
char* read(int length) {
    char* s = (char*)malloc(sizeof(char) * (length + 2));
    for (int i = 1; i <= length; i++) {
        char c;
        scanf("%c", &c);
        s[i] = c;
    }
    s[length + 1] = '\0';
    return s;
}

// 以字符串 t 求 next 數組,n 爲字符串長度
int* getNext(const char* t, int length) {
    int* next = (int*)malloc(sizeof(int) * (length + 1));
    next[1] = 0;
    for(int i = 2; i <= length; i++) {
        int j = next[i - 1];
        while(t[j + 1] != t[i] && j > 0) {
            j = next[j];
        }
        if(t[j + 1] == t[i]) {
            next[i] = j + 1;
        } else {
            next[i] = 0;
        }
    }
    return next;
}

void print(const char * t, const int* next, int n) {
    for (int i = 1; i <= n; i++) {
        printf("%c%c", t[i], i == n ? '\n' : '\t');
    }
    for (int i = 1; i <= n; i++) {
        printf("%d%c", next[i], i == n ? '\n' : '\t');
    }
}

int main() {
    int n;
    scanf("%d\n", &n);
    char* t = read(n);
    int* next = getNext(t, n);
//    print(t, next, n);
    printf("%d\n", n - next[n]);
}

歡迎關注我的個人博客以閱讀更多優秀文章:凝神長老和他的朋友們(https://www.jxtxzzw.com)

也歡迎關注我的其他平臺:知乎( https://s.zzw.ink/zhihu )、知乎專欄( https://s.zzw.ink/zhuanlan )、嗶哩嗶哩( https://s.zzw.ink/blbl )、微信公衆號( 凝神長老和他的朋友們 )
凝神長老的二維碼們

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