計蒜客 - 匹配格式
有一字符串 S,蒜頭君想在 S 中找到最長的子串 E,使得 S 滿足格式 “EAEBE”,其中 A, B 可以爲任意的 S 子串。也就是說子串 E 既是 S 的前綴也是 S 的後綴,同時還在 S 中間出現,但不與前綴 E 與後綴 E 重疊。
輸入格式
輸入一個字符串 S,由小寫字母構成,長度不超過 。
aaxoaaaaa
輸出格式
答案輸出佔一行,輸出一個整數,表示子串 E 的長度。
2
因爲求的是最長的 E
,而按照題意,E
不能重疊,所以 E
最長就是 length / 3
(此時 A
和 B
都是空串),因此從大到小枚舉所有可能的長度 len
就可以了。
for (int len = length / 3; len >= 1; len--) {
t
從 len + 1
開始枚舉,最多到 length - 2 * len
,因爲後面的 EBE
最少需要佔用 len + len
個長度,此時 B
是空串。
for (int t = len + 1; t <= length - 2 * len; t++) {
對於每一個枚舉的 t
,next[t]
表示從該字符 s[t]
開始,有長度爲多少的字符串,是與整個字符串開頭的那麼多個字符串相等的,顯然,爲了滿足題目要求,next[t]
必須大於 len
。
if (next[t] < len) {
continue; // 長度不滿足要求,繼續
}
現在,我們枚舉了開頭長度爲 len
的 E
,並且在中間那段找到了一個 t
開始的位置,可以保證有大於或者等於 len
個字符與字符串開頭是匹配的,所以,我們只需要需要找到最後一個 E
。
由於題目要求最後一個 E
必須是字符號結尾,所以直接判斷 next[length - len + 1]
是不是大於等於 len
就可以了。
if (next[length - len + 1] < len) {
continue;
}
如果滿足,那麼說明當前的 len
就是答案。在整個循環中保留最大的 len
即可。
ans = max(ans, len);
事實上,得到了一個答案,直接輸出就可以停止了,不需要繼續枚舉更短的 len
。
另外注意到 if (next[length - len + 1] < len)
判斷與 t
無關,所以提到循環外面,否則可能會超時。
#include <bits/stdc++.h>
#define MAX_LEN 1000007
using namespace std;
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 *getNext(const char *t, int n) {
int *next = (int *) malloc(sizeof(int) * (n + 1));
next[1] = n;
int p = 1;
while (p < n && t[p] == t[p + 1]) p++;
next[2] = p - 1;
int k = 2, l;
for (int i = 3; i <= n; i++) {
p = k + next[k] - 1;
l = next[i - k + 1];
if (i + l <= p) next[i] = l;
else {
int j = p - i + 1;
if (j < 0) j = 0;
while (i + j <= n && t[i + j] == t[j + 1]) j++;
next[i] = j;
k = i;
}
}
return next;
}
int main() {
char s[MAX_LEN] = {0};
scanf("%s", s + 1);
int length = strlen(s + 1);
int *next = getNext(s, length);
for (int len = length / 3; len >= 1; len--) {
if (next[length - len + 1] < len) {
continue;
}
for (int t = len + 1; t <= length - 2 * len; t++) {
if (next[t] < len) {
continue; // 長度不滿足要求,繼續
}
printf("%d\n", len);
return 0;
}
}
return -1;
}
歡迎關注我的個人博客以閱讀更多優秀文章:凝神長老和他的朋友們(https://www.jxtxzzw.com)
也歡迎關注我的其他平臺:知乎( https://s.zzw.ink/zhihu )、知乎專欄( https://s.zzw.ink/zhuanlan )、嗶哩嗶哩( https://s.zzw.ink/blbl )、微信公衆號( 凝神長老和他的朋友們 )