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
原创粉丝点击