FZU 2128 最长子串
Posted 小小八
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FZU 2128 最长子串相关的知识,希望对你有一定的参考价值。
题目链接:最长子串
思路:依次找出每个子串的在字符串中的首尾地址,所有子串先按照尾地址从小到大排序。然后首地址从小到大排。
遍历一遍每个子串的首地址和它后面相邻子串的尾地址之差-1, 第一个子串的首地址,字符串长度-最后一个子串的首地址-1的最大值就是ans。
st1----------ed1
-------st2------------ed2
例如这种情况说明,可能出现的一个ans 就是 ed2和st1之间的字符个数。这时候没有ed2最后一个字符,st1第一个字符,所以不包含str1和str2.
关于找每个子串的位置,有两种方法,kmp和strstr.
会找到多少个子串位置呢,最大当然不是n,而是字符串长度!结构体数组开小,RE了一个半点~~~
kmp AC 代码:
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; const int maxn = 1000005; struct Node { int st, ed; } node[maxn]; char s[maxn], t[1005][105]; int n, cnt, next[105]; bool cmp(Node a, Node b) { if (a.ed != b.ed) return a.ed < b.ed; else return a.st <= b.st; } void get_next(char p[]) { memset(next, 0, sizeof(next)); int len = strlen(p); int i = 0; next[0] = -1; int k = -1; while(i<len) { if (k == -1 || p[i] == p[k]) { i++; k++; next[i] = k; } else k = next[k]; } } void kmp(char s[], char p[]) { int lens = strlen(s); int lenp = strlen(p); int i = 0, j = 0; get_next(p); while(i<lens && j<lenp) { if (j == -1 || s[i] == p[j]) { i++; j++; } else j = next[j]; if (j == lenp) { node[cnt].st = i-lenp; node[cnt].ed = i-1; cnt++; j = next[j]; } } } int main() { while (scanf("%s", s) == 1) { scanf("%d", &n); for (int i = 0; i < n; i++) scanf("%s", t[i]); cnt = 0; for (int i = 0; i < n; i++) { kmp(s, t[i]); } sort(node, node + cnt, cmp); int ans = -1; for (int i=0; i<cnt-1; ++i) { int st = node[i].st; int ed = node[i+1].ed; ans = max(ans, ed - st - 1); } int len = strlen(s); if (cnt > 0) { ans = max(ans, node[0].ed); ans = max(ans, len-node[cnt-1].st-1); } else ans = len; printf("%d\n", ans); } }
strstr函数处理AC代码:
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; char s[1000010], p[110]; char str[1000010]; struct Node { int st, ed; }node[1000010]; int next[110]; int cnt; bool cmp(Node a, Node b) { if (a.ed != b.ed) return a.ed < b.ed; else return a.st <= b.st; } bool check(char s[], char p[]) { if (strstr(s, p)) return true; return false; } void solve(char s[], char p[], int pre) { // 开始没设pre 参数。这样每次找到的位置只是相对当前字符串的,不能直接设为node[cnt].st 和 node[cnt].ed. int lenp = strlen(p); if (check(s, p)) { int num = strstr(s, p) - s; node[cnt].st = num + pre; node[cnt].ed = num + pre + lenp - 1; cnt++; solve(s+num+lenp, p, pre+num+lenp); } } int main() { int n; while(~scanf("%s", s)) { cnt = 0; scanf("%d", &n); for (int i=0; i<n; ++i) { scanf("%s", p); solve(s, p, 0); } sort(node, node+cnt, cmp); int ans = 0; for (int i=0; i<cnt-1; ++i) { int st = node[i].st; int ed = node[i+1].ed; ans = max(ans, ed - st - 1); } int len = strlen(s); if (cnt > 0) { ans = max(ans, node[0].ed); ans = max(ans, len-node[cnt-1].st-1); } else ans = len; printf("%d\n", ans); } return 0; }
后话,感觉无论是kmp还是strstr都明显会超时,如kmp是 n*strlen(str),最大是10^3*10^6。然,并没有,而且题解貌似都是这样的解........
挺好的题,会的kmp,需要思考的方案。
以上是关于FZU 2128 最长子串的主要内容,如果未能解决你的问题,请参考以下文章
FZU 2216 The Longest Straight(最长直道)