题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4763
题目描述:
现有一字符串S,要求在S中找到最长的子串E,使得S满足格式“EAEBE”,其中A,B可以为任意的S子串。也就是说子串E既是S的前缀也是S的后缀,同时还在S中间出现,但不与前缀E与后缀E重叠。
解题思路:
学习KMP的第一道题。KMP的详解这篇文章写得很好:http://www.cnblogs.com/c-cloud/p/3224788.html,看完应该能理解前缀后缀概念和next数组的意义了(顺便给自己备忘下)。
好,那么有了上述储备知识后就可以来解题啦。已知next[i]表示的是字符串str中的一段,即“str[0]str[1] ... str[i-1]str[i]”这个字符串,的相同前后缀的最长长度,那么要在字符串S中找E,就直接从S的末位开始,假设k = next[S.length()-1],那么也就是说存在前缀“S[0]S[1] ... S[k-1]”与后缀“S[S.length()-k] ... S[S.length()-1]”相等,那么直接在S的子串“S[k]S[k+1] ... S[S.length()-k-1]”中寻找那段前缀就可以了。如果没有的话就减小前后缀长度-->原来程序减小的方法错误,直接递减是错误的,想差了,要i = next[i-1]才行,i即是前后缀相同的长度,这样的减小方式才能保证前后缀始终是一样,然后重新在新中间段中寻找即可。
嘛,说的不是很清楚,仅供参考用...
代码:
//#include <iostream> #include <cmath> #include <cstdio> #include <cstring> //#include <vector> //#include <algorithm>//C++中限定字符有next,用C++的库的话oj会对next报错 using namespace std; #define ll long long #define INF 0x3f3f3f3f3f #define MAX 1001000 char T[MAX], S[MAX]; int next[MAX]; /*void display(int n) { for(int i = 0; i < n; ++i) { printf("%d ", next[i]); } printf(" "); }*/ void getNext() { next[0] = 0; int len = strlen(T); int k = 0; for(int i = 1; i < len; ++i) { while(k > 0 && T[i] != T[k]) k = next[k-1]; if(T[i] == T[k]) k++; next[i] = k; } } int main() { //freopen("debug\in.txt", "r", stdin); //freopen("CON", "w", stdout); int i, j, k; int test; scanf("%d", &test); while(test--) { scanf("%s", T); memset(next, 0, sizeof(next)); getNext(); int len = strlen(T); //display(len); int ans = 0; i = next[len - 1]; //获取整个字符串的最长相同前后缀长度i bool flag = 0; //flag=1时表明找到题目要求的字符串了,跳出循环 while (!flag && i > 0) { //从这里开始,跳出循环条件为找到了字符串或者选取的长度还大于0 k = len - i - 1; //中间段的下界,同时也是搜寻下标 while(next[k] == 0 && k >= 2 * i - 1) //寻找中间段最右边next值不为0的字符 k--; while(k >= i * 2 - 1) { //明显中间的子串不能跟前缀重叠 if(next[k] >= i) { //找到子串了 ans = i; flag = 1; break; } else if (next[k] - 1 > 0) k = next[k] - 1; //否则向前继续寻找 else k--; //特判一下防止错过 } i = next[i-1]; //因为我的字符串下标是0 - n-1,所以是next[i-1] } printf("%d ", ans); } } /* 这里给一组杭电题目讨论区 @我嘞个娘哦 提供的数据做为参考 10 aaaaaaaaa aaaaba ababab ababdabab abdabdabdab aaabaabaaa abababab abdaab abdabcab abcabcabc output: 3 1 2 2 2 1 2 0 2 3 */