Life Forms 后缀数组 不小于k个字符串中的最长子串
来源:互联网 发布:淘宝新店推广 编辑:程序博客网 时间:2024/04/30 16:44
其实还是没搞太懂后缀数组这玩意...
简单来说就是求解不小于k个字符串中的最长子串,k=n/2
思路:将n个字符串连起来,中间用不同且没有在字符串中出现过的字符隔开,然后求后缀数组,再二分答案,判断每组的后缀是否出现在不小于k个的原串中。
求解SA,h数组都是照搬的网上的模板。对于每组的h[i]只要其大于等于目标长度,就让计数器+1,当计数器大于n/2即符合要求。
代码如下:
#include<stdio.h>#include<string.h>#include<cstdlib>using namespace std;#define Max 100200int sa[Max], height[Max], rank[Max];int wa[Max], wb[Max], ws[Max], wv[Max];char str[101][1005];int s_num[Max];//将str转换为int数组 int p = 0;int belong[101][2];//记录每个串的范围 int n;int cmp(int *r, int a, int b, int l){return (r[a] == r[b]) && (r[a + l] == r[b + l]);}void DA(int *r, int *sa, int n, int m){int i, j, p, *x = wa, *y = wb, *t;for (i = 0; i<m; i++) ws[i] = 0;for (i = 0; i<n; i++) ws[x[i] = r[i]]++;for (i = 1; i<m; i++) ws[i] += ws[i - 1];for (i = n - 1; i >= 0; i--) sa[--ws[x[i]]] = i; for (j = 1, p = 1; p<n; j *= 2, m = p) {for (p = 0, i = n - j; i<n; i++) y[p++] = i; for (i = 0; i<n; i++) if (sa[i] >= j) y[p++] = sa[i] - j; for (i = 0; i<n; i++) wv[i] = x[y[i]];for (i = 0; i<m; i++) ws[i] = 0;for (i = 0; i<n; i++) ws[wv[i]]++;for (i = 1; i<m; i++) ws[i] += ws[i - 1];for (i = n - 1; i >= 0; i--) sa[--ws[wv[i]]] = y[i]; for (t = x, x = y, y = t, p = 1, x[sa[0]] = 0, i = 1; i<n; i++)x[sa[i]] = cmp(y, sa[i - 1], sa[i], j) ? p - 1 : p++;}}void calheight(int *r, int *sa, int n) { ]int i, j, k = 0; for (i = 1; i <= n; i++) rank[sa[i]] = i; for (i = 0; i<n; height[rank[i++]] = k)for (k ? k-- : 0, j = sa[rank[i] - 1]; r[i + k] == r[j + k]; k++); }int id(int loc){for (int i = 0; i<n; i++)if (loc >= belong[i][0] && loc <= belong[i][1]) return i;return -1;}bool check(int len, bool output = false){int cnt = 0;int i = n + 1;//跳过插入的间隔符while (1){bool vis[101] = { 0 };while (i < p&&height[i] < len) i++;if (i >= p) break; vis[id(sa[i - 1])] = true;cnt=1;while (i < p&&height[i] >= len){if (!vis[id(sa[i])]){vis[id(sa[i])] = true;++cnt;}i++;}if (cnt > n / 2){if (output){for (int j = sa[i - 1]; j < sa[i - 1] + len; j++)printf("%c", s_num[j] + 'a' - 100);printf("\n");}else return true;}}return false;}int main(){int i, j;while (1){scanf("%d", &n);if (!n) break;scanf("%s", str[0]);belong[0][0] = 0; belong[0][1] = strlen(str[0]) - 1;if (n == 1){printf("%s\n", str[0]); continue;}for (i = 1; i<n; i++){belong[i][0] = belong[i - 1][1] + 2; scanf("%s", str[i]);belong[i][1] = belong[i][0] + strlen(str[i]) - 1; }for (p = i = 0; i<n; i++){int len = belong[i][1] - belong[i][0];for (j = 0; j <= len; j++){s_num[p++] = str[i][j] - 'a' + 100;//转为int数组 }s_num[p++] = i;}DA(s_num, sa, p, 130); calheight(s_num, sa, p-1); int l = 0, r = p - 1, mid; while (l<r){mid = (l + r + 1) / 2;if (check(mid)) l = mid;else r = mid - 1;}if (l == 0) printf("?\n\n");else{check(l, 1);printf("\n");}}return 0;}
0 0
- POJ 3294 Life Forms(不小于k个字符串中的最长子串 后缀数组)
- Life Forms 后缀数组 不小于k个字符串中的最长子串
- poj 3294 Life Forms(不小于k 个字符串中的最长子串)
- POJ 3415 Life Forms 给定n个字符串,求出现在不小于k个字符串中的最长子串。
- poj3294(不小于k个字符串中的最长子串---后缀数组)
- poj 3294 ( 后缀数组 不小于 k 个字符串中的最长子串 )
- POJ 3294 后缀数组:求不小于k个字符串中的最长子串
- poj 3294 不小于 k 个字符串中的最长子串(后缀数组+二分)
- 后缀数组(不小于k个字符串中的最长子串)
- POJ 3294 Life Forms (后缀数组,求出现在不少于k个字符串的最长子串)
- poj3294 Life Forms(后缀数组+大于k/2个字符串中含有的最长公共子串)
- POJ 3294 Life Forms(后缀数组求k个串的最长子串)
- POJ 题目3294Life Forms(后缀数组求超过k个的串的最长公共子串)
- poj 3294 Life Forms(n个字符串中 求公共子串长度超过k得最大子串 后缀数组)
- Poj 3294 Life Forms (后缀数组 在n个串中出现k次的最长公共子串并输出)
- hdu 3415 后缀数组 长度不小于 k 的公共子串的个数
- poj 3415 ( 后缀数组 长度不小于 k 的公共子串的个数)
- 后缀数组(长度不小于k的公共子串的个数)
- 线/进程所持有资源以及子线/进程所继承资源
- STL学习小结2
- LibGDX_4.2: 演员(Actor)
- UI基础-图片异步下载、KVO
- jQuery之dom操作(遍历节点)
- Life Forms 后缀数组 不小于k个字符串中的最长子串
- 指针类型学习总结-- this指针
- Code Forces 590 B. Chip 'n Dale Rescue Rangers(二分)
- Boyer-Moore算法--C语言实现(简单易懂)
- STL学习小结3
- C++ pair(对组)用法
- java BigDecimal介绍
- hello world
- C/C++ 中头文件相互包含引发的问题