题目描述
小明作为工厂的工程师,在开发网站时不小心写出了一个 Bug:当用户输入密码时,如果既和
自己的密码一致,也同时是另一个用户密码的 前缀 时,用户会跳转到 404 页。然而小明坚称:
我们的用户那么少,怎么可能触发这个 Bug……
机智的你,能不能帮小明确认一下这个 Bug 到底会不会触发呢? 样例输入:第一行输入一个整数 n(1≤n≤233333),表示工厂网站的用户数。接下来一共 n行,
每行一个由小写字母a-z组成的字符串,长度不超过 10,表示每个用户的密码。工厂的数据库
容量太小,所有密码长度加起来小于 466666。
样例输出:如果触发了 Bug 则输出一行Bug!,否则输出一行Good Luck!。
样例输入1
3
abc
abcdef
cdef
样例输出1
Bug!
样例输入2
3
abc
bcd
cde
样例输出2
Good Luck!
初步分析
这道题如果用朴素算法的话,如果有n个字符串则公有n*(n-1)种匹配方式所以暴力求解的平均复杂度大概是O(m*n^2)。肯定会被一些大的数据卡主的。而如果采用trie数的话,复杂度会直接降到线性级别O§.p是Trie树里的节点个数。那么怎么检测一个字符串是否其他字符串的前缀呢?其实很简单,我们只需要深度优先搜索Trie树(按从小到大的方式),值达到叶节点终端检查前面的路径是否出现过终端点(用flag来做标记)。
直接上代码
#include <iostream>
#include <string.h>
using namespace std;
const int MAX_N=233334;
const int MAX_C=26;
typedef struct trie {
int *ch[MAX_N];
int tot;
int cnt[MAX_N];
void init() {
tot = 0;
memset(ch, NULL, sizeof(ch));
memset(cnt, 0, sizeof(cnt));
}
void insert(char *str) {
int p = 0;
for (int i = 0; str[i]; ++i) {
if (ch[p]==NULL){
ch[p]=new int[MAX_C];
memset(ch[p],-1, sizeof(int)*MAX_C);
}
if(ch[p][str[i]-'a']==-1){
ch[p][str[i]-'a']=++tot;
}
p=ch[p][str[i]-'a'];
}
cnt[p]++;
}
bool stop= false;
void dfs(int p,int flag1){
if(stop)
return ;
if(cnt[p]>0){
if(flag1==1){
stop= true;
return;
}
flag1=1;
}
if(ch[p]!=NULL){
for(int i=0;i<26;++i){
if(ch[p][i]!=-1){
dfs(ch[p][i],flag1);
}
}
}
}
}Trie;
int main() {
int n;
cin>>n;
Trie arr;
arr.init();
for(int i=0;i<n;++i){
char temp[20];
scanf("%s",temp);
arr.insert(temp);
}
arr.dfs(0,0);
if(arr.stop)
cout<<"Bug!"<<endl;
else
cout<<"Good luck"<<endl;
return 0;
}