题目链接
字典树题目,给定多个单词,如果存在由两个单词构成的单词,就输出,按字典序输出,用字典序,先正序插入,再逆序插入,然后查找就正序查找,逆序查找,找到就标记到vis数组里,最后再遍历一遍vis就好了。用set存答案,方便排序输出。
代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
#include <map>
#include <set>
using namespace std;
#define int128 _int128;
#define reg register;
typedef long long ll;
typedef double db;
const int mod=1e9+7;
const int maxn=1e5+2;
const double eps=0.00000001;
/*inline void print(int128 x){
if(x<0){
putchar("-");
x=-x;
}
if(x>9) print(x/10);
putchar(x%10+'0');
}*/
char s[maxn][55],vs[maxn][55];
int b[maxn][27],vb[maxn][27],k1=1,k2=1,vcolor[maxn],color[maxn],vis[55];
set<string>a;
inline void verse(int x){
int len=strlen(s[x]);
for(register int i=len-1,j=0;i>=0;--i,++j) vs[x][j]=s[x][i];
}
inline void insert1(int x){
int len=strlen(s[x]);
int p=0;
for(register int i=0;i<len;++i){
int c=s[x][i]-'a';
if(!b[p][c]){
b[p][c]=k1++;
}
p=b[p][c];
}
color[p]=1;
}
inline void insert2(int x){
int len=strlen(vs[x]);
int p=0;
for(register int i=0;i<len;++i){
int c=vs[x][i]-'a';
if(!vb[p][c]){
vb[p][c]=k2++;
}
p=vb[p][c];
}
vcolor[p]=1;
}
inline void find1(int x,int len){
int p=0;
for(register int i=0;i<len;++i){
vis[i]=0;
int c=s[x][i]-'a';
p=b[p][c];
vis[i]+=color[p];//如果从0-i组成的单词存在,vis就+1.
}
}
inline void find2(int x,int len){
int p=0;
for(register int i=0;i<len;++i){
int c=vs[x][i]-'a';
p=vb[p][c];
vis[len-i-2]+=vcolor[p];//同上注释
}
}
int main(){
int cnt=0;
while(scanf("%s",s[++cnt])!=EOF){
verse(cnt);
insert1(cnt);
insert2(cnt);
}
for(register int i=1;i<=cnt;++i){
int len=strlen(s[i]);
if(len==1) continue;
find1(i,len);
find2(i,len);
for(register int j=0;j<len;++j){
if(vis[j]==2){//存在两个单词构成的单词。
string tmp=s[i];
a.insert(tmp);
break;
}
}
}
set<string>::iterator it;
for(it=a.begin();it!=a.end();++it){
printf("%s\n",(*it).c_str());
}
}