这里的讲解超级棒!!必戳!: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; }