#include <iostream>
#include <string.h>
#include <queue>
using namespace std;
#define MAX 26
struct node;
typedef struct node *NumTree;
struct node
{
int tag;
NumTree ans[MAX];
};
NumTree init(NumTree T)
{
int i;
T=new struct node;
for(i=0;i<MAX;i++)
{
T->tag=0;
T->ans[i]=NULL;
}
return T;
}
void insert(NumTree T,char str[])
{
NumTree Q=T,S=NULL;
int len=strlen(str);
int i,id;
for(i=0;i<len;i++)
{
id=str[i]-'a';
if(Q->ans[id]==NULL)
{
S=new struct node;
int j;
for(j=0;j<MAX;j++)
{
S->ans[j]=NULL;
S->tag=0;
}
Q->ans[id]=S;
Q=Q->ans[id];
}
else
{
Q=Q->ans[id];
}
}
Q->tag=1;
}
int find(NumTree T,char str[])
{
NumTree Q=T;
int len=strlen(str);
int i,id;
queue<int>Stack;
for(i=0;i<len;i++)
{
id=str[i]-'a';
if(Q->ans[id]!=NULL)
{
Q=Q->ans[id];
}
if(Q->tag && i<len)//find sepraste point
{
Stack.push(i);
}
}
while(!Stack.empty())
{
int now=Stack.front();
now++;
bool OK=true;
Stack.pop();
Q=T;
while(str[now])
{
id=str[now++]-'a';
if(Q->ans[id]==NULL)
{
OK=false;
break;
}
Q=Q->ans[id];
}
if(OK && Q->tag)
return 1;
}
return 0;
}
int main()
{
char str[50011][20];
NumTree T=NULL;
int x=0;
T=init(T);
while(gets(str[x]) && str[x][0]!='\0')
{
insert(T,str[x]);
x++;
}
int u;
for(u=0;u<x;u++)
{
if(find(T,str[u])==1)
cout<<str[u]<<endl;
}
return 0;
}
搞了一下午····
不得不说还是有一些收获,RE的次数最多,
这里要说一下,RE分两种,一种越界,一种是栈溢出,
这里在定义str的时候,
如果定义str[50001][100],就会栈溢出,可见字典树对字符长度的要求很高,不能太长。
整个代码的思路就是在insert同时的时候标记,一个字符如果是一个字符串的结尾字符,那么标记,
在find的时候,如果找到了一个标记,找到了A个标记,说明这个字符串里含有A个字符串,但无法确定这A个字符串是否是紧邻的,这里需要用STACK或者QUEUE,最好还是用STACK,依次记录有标记的下标,然后从后往前开始查询,
这里还有一个小细节,在查询的时候now++,因为top回来的now是一个字符的结尾,重新遍历的时候应该是从找到标记的字符的后一个字符开始。
然后如果有两个以上标记是怎么回事呢?
如果
abcdefg
1001001
有三个标记,这时候从最后一个1开始找,然后从倒数第二个1找,而这里的1代表,至少字典里有a,abcd,abcdefg三个字符串(也可能有defg,bcd等等),也就是说我从标记的下一个字符开始找起,标记的前半部分已经肯定在字符串里了(也就是组成该字符串的前半段),只需要证明从标记开始的字符串也在字典树里,那么就满足该字符串由两个字符串构成,输出即可。
这题还有一个思路,就是把每一个字符串在不同位置“砍一刀”,变成两个字符串,然后find(str1)find(str2),如果都能找到,那么就说明它(这个字符串)有两个字符串构成,这个代码我也实现了,但是不知道为什么一直RE,可能是迭代或者递归的层数太多了(find要递归,如果字符串很长的话,也要砍很多刀)。暂时我还没有想到比较好的优化方案。砍刀也许可以用二分查找实现,但那仍然依赖输入。对效率提升不一定十分明显。
#include <iostream>
#include <string.h>
using namespace std;
#define MAX 26
struct node;
typedef struct node *NumTree;
struct node
{
NumTree ans[MAX];
};
NumTree init(NumTree T)
{
int i;
T=new struct node;
for(i=0;i<MAX;i++)
T->ans[i]=NULL;
return T;
}
void insert(NumTree T,char str[])
{
NumTree Q=T,S=NULL;
int len=strlen(str);
int i,id;
for(i=0;i<len;i++)
{
id=str[i]-'a';
if(Q->ans[id]==NULL)
{
S=new struct node;
int j;
for(j=0;j<MAX;j++)
S->ans[j]=NULL;
Q->ans[id]=S;
Q=Q->ans[id];
}
else
{
Q=Q->ans[id];
}
}
}
int find(NumTree T,char str[])
{
NumTree Q=T;
int len=strlen(str);
int i,id;
int tag=1;
for(i=0;i<len;i++)
{
id=str[i]-'a';
if(Q->ans[id]!=NULL)
Q=Q->ans[id];
else
{
tag=0;
break;
}
}
return tag;
}
void FreeTree(NumTree T)
{
int i;
for(i=0;i<MAX;i++)
{
if(T->ans[i]!=NULL)
FreeTree(T->ans[i]);
}
free(T);
}
int main()
{
char str[50011][100];
NumTree T=NULL;
int x=0;
T=init(T);
while(gets(str[x]) && str[x][0]!='\0')
{
insert(T,str[x]);
x++;
}
int u;
for(u=0;u<x;u++)
{
int i,j,k=1;
int len=strlen(str[u]);
char str1[100],str2[100];
while(k<len)
{
for(i=0;i<k;i++)
str1[i]=str[u][i];
str1[i]='\0';
for(j=0;i<len;i++,j++)
str2[j]=str[u][i];
str2[j]='\0';
if(find(T,str1) && find(T,str2))
{
printf("%s\n",str[u]);
break;
}
k++;
}
}
//FreeTree(T);
return 0;
}