题意很好理解就不说了,然后这道题其实不用字典树更简单,但是为了练习trie树就写了一下,1A了哈哈,再对比了一下讨论区的大神代码,发现我还是写复杂了。。。
思路:
想到利用字典树,继承字典树原有机制,从底端叶子向上找,每条路径最先找
到的分叉点再往下(从叶子找上来的这条路)一个字符即为所求(特殊情况,
如果节点处单词已结束,那么就输出整个单词好了),也就是从上往下找到的
第一个不是路径重合(has_same_path = true)的情况或者是is_word =
true的情况,用遍历二叉树的方法遍历整个树得到所有前缀。
判断has_same_path的情况很简单,如果当前tmp->next[num]不为空,则
一定has_same_path
,至于pos则是为了让答案按顺序输出用的
代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102
|
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm>
#define MAXN 1005
using namespace std;
struct node { node *next[26]; bool has_same_path; bool is_word; int pos; node() { memset(next , 0 , sizeof(next)); has_same_path = is_word = false; pos = -1; } }trie[100005]; int trie_num;
struct out { char s[21]; int pos; out() { memset(s , 0 , sizeof(s)); pos = -1; } }ans[MAXN];
int n = 1,id; char str[MAXN][21],tmp_str[21];
bool cmp(out a , out b) { return a.pos < b.pos; }
void insert(char *s , int pos) { int len = strlen(s); node *now = &trie[0]; for(int i = 0;i < len;i ++) { int num = s[i] - 'a'; if(!now->next[num]) now->next[num] = &trie[++trie_num]; else now->next[num]->has_same_path = true; now = now->next[num]; if(now->pos == -1) now->pos = pos; } now->is_word = true; now->pos = pos; }
void cons(node *now , int k) { if(!now->has_same_path || now->is_word) { tmp_str[k] = 0; memcpy(ans[++id].s , tmp_str , k); ans[id].pos = now->pos; now->is_word = false; if(!now->has_same_path) return ; } for(int i = 0;i < 26;i ++) { if(now->next[i]) { tmp_str[k] = i + 'a'; cons(now->next[i] , k + 1); } } }
int main() { while(scanf("%s" , str[n]) != EOF) { insert(str[n] , n); n ++; } n --; trie[0].has_same_path = true; cons(&trie[0] , 0); sort(ans + 1 , ans + n + 1 , cmp); for(int i = 1;i <= n;i ++) printf("%s %s\n",str[i] , ans[i].s); return 0; }
|
其实空间没必要开那么大,为了省事就乱开了