这里的讲解超级棒!!必戳!:https://www.cnblogs.com/TheRoadToTheGold/p/6290732.html
其中最重要的是字典树数组写法:s[i][j]=k,表示编号为i的节点的第j个孩子是编号为k的节点
我的理解就是觉得,如果字符串的数量一大起来,题意是关于查询“相同前缀”的,那么就用字典树了!!!
模板:
更多模板请见链接。
例题:糟糕的Bug
大致思路:
找相同前缀的字符串。。字典树模板题。。
这里的关键在于是要无视各个字符串的输入顺序,所以可能前面输的字符串包含了后面的,也可能后面的包含了前面的。
针对这个问题,就注意两个思路:
①如果当前输入的包含了前面的,那么在插入当前字符串的时候,会达到前面的叶子结点&&没有新开结点(即一直用的是前面的结点)。
②如果当前输入的被前面的包含了,那么在插入当前字符串,插入完成之后,没有新开结点。
有了这俩思路,就知道判断语句怎么写了。需要用一个e[maxn],e[k]表示第k个结点是否为叶子结点。需要在插入过程中通过判断temp==tot来看有没有新开结点。
AC代码:
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
const int maxn=566666;
int s[maxn][26];
bool e[maxn];
int tot=0;
void init()
{
memset(s,-1,sizeof(s));
memset(e,false,sizeof(e));
}
bool insert(char *t,int len) //传入的字符串和其长度
{
int temp=tot;
int p=0;
for(int i=0;i<len;i++)
{
if(s[p][t[i]-'a']==-1) s[p][t[i]-'a']=++tot;
p=s[p][t[i]-'a']; //之前这里想当然的写成p=tot,不对!!因为如果没有新开结点呢?
if(e[p]==true && tot==temp) return false;
}
if(tot==temp) return false;
e[p]=true;
return true;
}
int main()
{
init();
int n;
cin>>n;
bool flag=true;
while(n--)
{
char t[12];
scanf("%s",t);
if(flag)
flag=insert(t,strlen(t));
}
if(flag==true)
cout<<"Good Luck!";
else
cout<<"Bug!";
return 0;
}