計蒜客 - 重複的密文
蒜頭君收到了一串密文,但是由於接收器壞了,他不停的重複接收,終於,蒜頭君把插頭拔了,機器停止了,但是蒜頭君已經收到了一個很長字符串,它是由某個原始串不停的重複形成了,因爲斷電,最後一遍也不一定是完整的。蒜頭君現在想知道這個原始串的最短可能長度是多少。
輸入格式
第一行輸入一個正整數 ,表示這個字符串的長度。
第二行輸入一個字符串,全部由小寫字母組成。
8
cabcabca
輸出格式
答案輸出,輸出最短的可能長度。
3
這道題是求 KMP 的最小循環節。
仔細觀察 next[]
數組,可以發現,如果出現循環,那麼除了第一個循環節的值都是 ,從第二個循環節開始,包括最後一個,都是遞增的,而且記錄了最長公共前綴。
所以利用 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 )、微信公衆號( 凝神長老和他的朋友們 )