HDU1671
题目大意:给你n个长度小于10的电话号码,让你判断是否存在一个号码是其他号码的前缀,若存在,输出NO,否则输出YES。
分析:大量数据查询短字符串,一看就是Tire树的题。把n个号码存入之后,遍历查询这n个号码,如果存在某一个号码所对应的节点的num值大于1,那么就说明该组号码有不止一个这样的前缀,即:存在一个号码是其他号码的前缀,跳出循环输出结果即可;如果所有节点的num值都不大于1,那么就说明这组号码是合法的,输出YES。
实现代码如下:
#include <cstdio> #include <cstdlib> #include <iostream> using namespace std; #define son_num 30 //字符串中包含的字符个数 #define maxn 10 //单词的最大长度 struct tire { int num; //纪录到达该节点的字符串的个数,即相同前缀数 bool terminal; //如果terminal=true,表示当前点为该字符串最后一个字符 struct tire *next[son_num]; //纪录下一个节点 }; tire *root; char str0[10001][maxn]; tire *init() //创建新节点 { tire *p=(tire *)malloc(sizeof(tire)); for(int i=0;i<son_num;i++) p->next[i]=NULL; p->terminal=false; p->num=0; return p; } void insert(tire *root,char str[]) //插入操作 { int i=0; tire *p=root; while(str[i]!='\0') { if(!p->next[ str[i]-'0' ]) //如果不存在,建立新节点 p->next[ str[i]-'0' ]=init(); p=p->next[ str[i]-'0' ]; p->num++; i++; } p->terminal=true; } bool find(tire *p,char str[]) //查找操作 { int i=0; while(str[i]!='\0'&&p->next[ str[i]-'0' ]) { p=p->next[ str[i]-'0' ]; i++; } if(str[i]=='\0'&&p->num>1) return true; //查找前缀 return false; } void del(tire *root) //清空操作 { for(int i=0;i<son_num;i++) if(root->next[i]!=NULL) del(root->next[i]); free(root); } int main() { int n,t; cin>>t; while(t--) { root=init(); //创建根结点 scanf("%d",&n); for(int i=0;i<n;i++) //建立字典树 { cin>>str0[i]; insert(root,str0[i]); } bool flag=true; for(int i=0;i<n;i++) //查找操作 if(find(root,str0[i])) { flag=false; break; } if(flag) puts("YES"); else puts("NO"); del(root); //释放字典树占用的空间 } return 0; }
POJ3630:
这题和上一题是一模一样的,不过神奇的是拿上一个代码交的话就是TLE
原因应该是动态建立链表的话每一次开辟新空间需要花费大量的时间吧,这题用的是静态链表,即用数组模拟链表。
实现代码如下:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; #define son_num 10 #define maxn 100010 struct node { int num; //到达该节点的字符串的个数 bool terminal; //是否为最后一个字符 int next[son_num]; //子节点 void init() //初始化子节点 { num=1; terminal=false; for(int i=0;i<son_num;i++) next[i]=0; } }tire[maxn]; bool flag; int sum; //节点数 void insert(char word[]) { int index=0; int branch,i=0; int len=strlen(word); while(word[i]!='\0') { branch=word[i]-'0'; if(tire[index].next[branch]) { index=tire[index].next[branch]; //将此节点指向下一个节点 tire[index].num++; //下一个节点的字母数加1 } else { sum++; //开辟一个新节点 tire[sum].init(); //初始化 tire[index].next[branch]=sum; //将当前节点的后续指向新节点 index=sum; } if(i==len-1) tire[index].terminal=true; if(tire[index].num>1&&tire[index].terminal) flag=true; i++; } } int main() { int n,m; char str[15]; cin>>n; while(n--) { cin>>m; tire[0].init(); sum=0; flag=false; while(m--) { cin>>str; if(!flag) insert(str); } if(flag) puts("NO"); else puts("YES"); } return 0; }