常规做法是枚举每个字符串每个位置,时间复杂度O(n*len*len),(建字典树O(n*len))。
然而我看这题第一眼想的是时间复杂度O(n*len)的算法。。就是建正反两棵字典树,每个字符串跑分别跑正反一遍字典树,再看看正反跑的结果能不能拼成原串。
然而常数太大了点,并没什么卵用。。
1 #include<cstdio> 2 #include<cstring> 3 using namespace std; 4 #define MAXL 22 5 #define MAXN 50100 6 7 int ch0[MAXN*MAXL][26],tn0,ch1[MAXN*MAXL][26],tn1; 8 bool flag[2][MAXN*MAXL]; 9 void insert(char *s){ 10 int x=0,len=strlen(s); 11 for(int i=0; i<len; ++i){ 12 int y=s[i]-'a'; 13 if(ch0[x][y]==0) ch0[x][y]=++tn0; 14 x=ch0[x][y]; 15 } 16 flag[0][x]=1; 17 x=0; 18 for(int i=len-1; i>=0; --i){ 19 int y=s[i]-'a'; 20 if(ch1[x][y]==0) ch1[x][y]=++tn1; 21 x=ch1[x][y]; 22 } 23 flag[1][x]=1; 24 } 25 26 char path[MAXL]; 27 bool vis[2][MAXL]; 28 void query(int len){ 29 memset(vis,0,sizeof(vis)); 30 int x=0; 31 for(int i=0; i<len; ++i){ 32 int y=path[i]-'a'; 33 if(ch0[x][y]==0) break; 34 x=ch0[x][y]; 35 if(flag[0][x]) vis[0][i]=1; 36 } 37 x=0; 38 for(int i=len-1; i>=0; --i){ 39 int y=path[i]-'a'; 40 if(ch1[x][y]==0) break; 41 x=ch1[x][y]; 42 if(flag[1][x]) vis[1][i]=1; 43 } 44 } 45 void dfs(int x,int k){ 46 if(flag[0][x]){ 47 query(k); 48 bool ishat=0; 49 for(int i=1; i<k; ++i){ 50 if(vis[0][i-1] && vis[1][i]){ 51 ishat=1; 52 break; 53 } 54 } 55 if(ishat){ 56 for(int i=0; i<k; ++i) putchar(path[i]); 57 putchar(' '); 58 } 59 } 60 for(int i=0; i<26; ++i){ 61 if(ch0[x][i]){ 62 path[k]=i+'a'; 63 dfs(ch0[x][i],k+1); 64 } 65 } 66 } 67 int main(){ 68 char str[MAXL]; 69 while(~scanf("%s",str)) insert(str); 70 dfs(0,0); 71 return 0; 72 }