您的位置:首页 > 其它

Corporate Identity - HDU 2328(多串求共同子串)

2015-08-19 09:29 302 查看
题目大意:给你N(2-4000)个字符串,求出来他们的共同子串

分析:因为上次就说了再出现这种题就不用那种暴力的做法了,于是看了一些别的知识,也就是后缀树,把一个字符串的所有的后缀全部都加入字典树,然后用别的串去匹配,这样匹配的时候速度那是飕飕的啊,不过第一次我把前N-1个串的所有前缀搞进了字典树里面,然后想如果某个节点被访问N-1次,并且第N个串也能访问到此节点,那么这一定就是他们的共同子串了,不过总归是太天真,直接返回MLE,一细琢磨,想着最糟糕的情况也就是有8000(N)个串,每个串都不相同,并且每个串的长度是200(len),那么空间复杂度应该是 len*(len+1)/2*N*26 大约理论上最糟糕的情况就是41亿内存,不超才见鬼了呢于是又换一种想法,如果只把第一个串的所有后缀加入字典树不就行了?因为求的是共同子串,第一个串也肯定包括所有串的共同子串,这样内存开销就会降到len*(len+1)/2*26大约50w不到,比较容易接受了。

下面是AC代码:
==========================================================================================================

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<stdlib.h>
using namespace std;

const int MAXN = 26;
const int MAXM = 1007;
const int oo = 1e9+7;

struct node
{
int times;
node *next[MAXN];
};

int BuildTrie(node *head, char s[], int x)
{
int i, k, depth = 0;
node *P = head;

for(i=0; s[i]; i++)
{
k = s[i] - 'a';
if(P->next[k] == NULL)
{
if(x != 1)
break;
P->next[k] = new node();
}

P = P->next[k];

if(P->times + 1 >= x)
{///如果此节点是本个串访问过或者上个节点访问过
P->times = x;
depth++;
}
else break;
}

return depth;
}
void clearTrie(node *head)
{///销毁树
node *P = head;

for(int i=0; i<MAXN; i++)
{
if(P->next[i] != NULL)
clearTrie(P->next[i]);
}

free(P);
}

int main()
{
int i, j, N;

while(scanf("%d", &N), N)
{
node *head = new node();
char s[MAXM]={0}, ans[MAXM]={0};

for(i=1; i<N; i++)
{
scanf("%s", s);
for(j=0; s[j] != '\0'; j++)
BuildTrie(head, s+j, i);
}
scanf("%s", s);

int Max = 0;

for(j=0; s[j] != '\0'; j++)
{
int len = BuildTrie(head, s+j, N);
char p[MAXM] = {0};

strncpy(p, s+j, len);

if(Max < len || (Max==len && strcmp(ans, p) > 0))
strcpy(ans, p), Max = len;
}

if(ans[0] == 0)
printf("IDENTITY LOST\n");
else
printf("%s\n", ans);

clearTrie(head);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: