做了一道POJ 2001,对TRIE树的思想差不多理解了。其实TRIE树的思想很简单,就是建树,每个节点都有26个子节点(如果是数字的话,那就是10个),然后每个单词从头到尾按照树的深度找下去,最后所有这些单词就挂在TRIE树上啦。
对于TRIE树的操作有:插入、删除、搜索等等。每个操作都很重要,删除如果没有的话在多组数据中就基本上要MLE了,这道题就是这样,一开始我没有做删除操作,MLE了5次。
题意:给你n个数(n <= 10000),问这些数中有没有某个数是另一个数的前缀,比如111和1110。有就输出NO,否则就输出YES。
思路很简单:因为是前缀,因此可以维护TRIE树,维护好之后,再去从TRIE树上找每个数字,如果某个数字已经找到它应该到的结点之后,还能再往下找到其他的数,那就说明满足题目说的条件了,退出判断即可。这种字符串匹配的题目,一开始可能会想到KMP,但是想想如果每个字符都和其他字符去做一遍KMP,那得O(n^2)的复杂度,肯定是要超时的。
顺便吐一个自己的槽,指针没学好真伤不起,malloc和free都用得不溜。
Code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n;
char a[10001][11];
struct node
{
struct node *next[10];
};
void insert(node *root, const char *tar)
{
if(root == NULL || *tar == '\0')
return;
int id;
node *p = root;
while(*tar)
{
id = *tar - '0';
if(p -> next[id] == NULL)
{
node *temp = (node *)malloc(sizeof(node));
for(int i = 0; i < 10; i ++)
temp -> next[i] = NULL;
p -> next[id] = temp;
}
p = p -> next[id];
tar ++;
}
}
bool search(node *root, const char *tar)
{
int id;
node *p = root;
while(*tar && p != NULL)
{
id = *tar - '0';
p = p -> next[id];
tar ++;
}
for(int i = 0; i < 10; i ++)
if(p -> next[i] != NULL)
return true;
return false;
}
void delnode(node *tar)
{
int i;
for(int i = 0; i < 10; i ++)
{
if(tar -> next[i] != NULL)
delnode(tar -> next[i]);
}
free(tar);
}
int main()
{
int cse, t = 1;
scanf("%d", &cse);
while(cse --)
{
node *root = (node *)malloc(sizeof(node));
for(int i = 0; i < 10; i ++)
root -> next[i] = NULL;
scanf("%d", &n);
for(int i = 0; i < n; i ++)
{
scanf("%s", a[i]);
insert(root, a[i]);
}
bool yes = true;
for(int i = 0; i < n; i ++)
if(search(root, a[i]))
{
yes = false;
break;
}
if(yes)
printf("Case %d: YES\n", t ++);
else
printf("Case %d: NO\n", t ++);
delnode(root);
}
}