http://acm.hdu.edu.cn/showproblem.php?pid=1247
题意:给出一堆单词,求哪些单词是其中某两个单词拼接起来的。
题解:用字典树存储所有的单词,标记结束点,再次遍历单词的时候如果遍历过程遇到结束点则表明有单词是该单词的前缀,查找后半段字母(后缀)看看最后能不能遇到结束点,如果遇到了则该单词是某两个单词的前后缀,可以输出。详看注释。
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<math.h>
#include<string>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<ctime>
#define ll long long
#define inf 0x3f3f3f3f
const double pi=3.1415926;
using namespace std;
int maxx=50005;
typedef struct node
{
int flag;///判断是否单词在这里就完了,作为前缀
node *next[27];
};
node* root=new node();///根节点始终为空
void insert(char* s)
{
node* p=root;
int len=strlen(s);
for(int i=0;i<len;i++)
{
int x=s[i]-'a';
if((p->next[x])==NULL)///当前遍历到的字母还没有开创节点
{
p->next[x]=new node();///新开一个节点
p=p->next[x];
}
else
{
p=p->next[x];
}
}
p->flag=1;///标记有单词在这里结束
}
int find2(char*s ,int now)///查后缀
{
node* p=root;
int len=strlen(s);
int i;
for(i=now;i<len;i++)///从now下标开始查询后缀,一直找
{
int x=s[i]-'a';
p=p->next[x];
if(p!=NULL)
{
if(i==(len-1) && p->flag==1)///s[now]-s[len-1]即后缀,是完整的单词
return 1;
}
else
return 0;
}
return 0;
}
int find(char* s)///查前缀,查到转后缀
{
node* p=root;
int len=strlen(s);
int i;
for(i=0;i<len;i++)
{
int x=s[i]-'a';
p=p->next[x];///进入当前字母的节点
if(p!=NULL)
{
if(p->flag==1 && i!=(len-1) && find2(s,i+1))///有单词到这里断了,即有前缀,不能是这个单词本身,所以后续还要有字母
return 1; ///如果find2成功才可以return 1,否则继续,可能还有别的前缀和后缀单词
}
else
return 0;
}
return 0;
}
int main()///hdu1247 字典树
{
int i=0;
char a[maxx][30];
while(scanf("%s",a[i])!=EOF)
{
insert(a[i]);
i++;
}
for(int j=0;j<i;j++)
{
if(find(a[j]))
printf("%s\n",a[j]);
}
return 0;
}
没有看到纯数组模拟字典树的题解代码,不得不手动写指针,困扰了挺长时间。看到有用map和string解决的,感觉那不是正道,还是把字典树学了。