模板解决了五个问题,插入,删除,查询是否存在这个单词,查询以这个字符串为前缀的单词数量,查询这个单词是否有前缀
放两篇解析,这里只放模板,因为我自己觉得这两篇解析该说的都说了,我暂时没有新的领悟
下面可以ACHDU1251
#include<cstdio>//https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/trie-tree-de-shi-xian-gua-he-chu-xue-zhe-by-huwt/
#include<iostream>//https://blog.csdn.net/qq_43906740/article/details/96474307?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0.essearch_pc_relevant&spm=1001.2101.3001.4242
#include<string>
#include<cstring>
using namespace std;
const int N=1e7+10;
struct node {
int isEnd;//true表示这是个尾节点,从根节点找到这里是一个单词
int prefix;//以这个字符串为前缀的单词数 如果该节点是根节点,代表单词数
int next[27];//子节点地址 数组下标是字符映射 从0开始 假设最小的字符是'x',那么每个字符的值为'y'-'x'
} trie[N];
int cnt;//cnt为trie的下标
string read(){
char ch=getchar();string a="";
while(ch!='\n'){
a+=ch;
ch=getchar();
}
return a;
}
inline void init() {
for(int i=0; i<=cnt; i++) {
trie[i].isEnd=0;
trie[i].prefix=0;
memset(trie[i].next,0,sizeof(trie[i].next));
}
cnt=0;//0是根节点
}
inline void insert(string word) { //插入单词
int len=word.size();
int now=0;//now代表当前节点在树中的下标
for(int i=0; i<len; i++) {
int ch=word[i]-'a';//字符映射
if(!trie[now].next[ch]) { //如果这个字符没被开辟
trie[now].next[ch]=++cnt;
}//如果开辟就不用再开辟了,直接用即可
trie[now].prefix++;//更新前缀数
now=trie[now].next[ch];//更新地址
}
trie[now].prefix++;//更新前缀数
trie[now].isEnd=true;//这是尾节点
}
inline bool searchExit(string word) { //查询是否存在这个单词
int now=0,len=word.size();
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //没这条边,所以不存在这个字符串
return false;
}
now=trie[now].next[ch];
}
return trie[now].isEnd;//返回是否有字符串在该点结束
}
inline int searchPrefix(string word) { //查询以这个字符串为前缀的单词数量
int now=0,len=word.size();
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //没这条边,所以不存在这个字符串,更不存在以其为前缀的单词
return false;
}
now=trie[now].next[ch];;
}
return trie[now].prefix;//查询前缀数
}
inline bool searchExitPrefix(string word) { //查询这个单词是否有前缀
int now=0,len=word.size();
for(int i=0; i<len; i++) {
if(trie[now].isEnd) return true;//如果有点在遍历字符串word的路径上且这个点是尾点,那么已经遍历到的字符串就是这个字符串的前驱
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //之前的边不是前缀,又没这条边,所以不存在前缀
return false;
}
now=trie[now].next[ch];;
}
return trie[now].isEnd;//相同也算存在前缀(根据题意更改)
}
void Delete(string word) { //删除所有前缀等于给定字符串的单词
int now=0,len=word.size();
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //没这条边,所以不存在这个字符串,更不存在以其为前缀的单词
return ;
}
now=trie[now].next[ch];
}
trie[now].isEnd=false;
memset(trie[now].next,0,sizeof(trie[now].next));
int t=trie[now].prefix;
trie[now].prefix=0;
now=0;
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
trie[now].prefix-=t;
now=trie[now].next[ch];
}
}
int main() {
init();
ios::sync_with_stdio(false);
string a;
while(1){
a=read();
if(a.empty()) break;
insert(a);
}
while(cin>>a){
int t=searchPrefix(a);
printf("%d\n",t);
}
return 0;
}
下面可以ACHDU5687
#include<cstdio>//https://leetcode-cn.com/problems/implement-trie-prefix-tree/solution/trie-tree-de-shi-xian-gua-he-chu-xue-zhe-by-huwt/
#include<iostream>//https://blog.csdn.net/qq_43906740/article/details/96474307?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_baidulandingword~default-0.essearch_pc_relevant&spm=1001.2101.3001.4242
#include<string>
#include<cstring>
using namespace std;
const int N=1e7;
struct node {
int isEnd;//true表示这是个尾节点,从根节点找到这里是一个单词
int prefix;//以这个字符串为前缀的单词数 如果该节点是根节点,代表单词数
int next[27];//子节点地址 数组下标是字符映射 从0开始 假设最小的字符是'x',那么每个字符的值为'y'-'x'
} trie[N];
int cnt;//cnt为trie的下标
string read() {
char ch=getchar();
string a="";
while(ch!='\n') {
a+=ch;
ch=getchar();
}
return a;
}
inline void init() {
for(int i=0; i<=cnt; i++) {
trie[i].isEnd=0;
trie[i].prefix=0;
memset(trie[i].next,0,sizeof(trie[i].next));
}
cnt=0;//0是根节点
}
inline void insert(string word) { //插入单词
int len=word.size();
int now=0;//now代表当前节点在树中的下标
for(int i=0; i<len; i++) {
int ch=word[i]-'a';//字符映射
if(!trie[now].next[ch]) { //如果这个字符没被开辟
trie[now].next[ch]=++cnt;
}//如果开辟就不用再开辟了,直接用即可
trie[now].prefix++;//更新前缀数
now=trie[now].next[ch];//更新地址
}
trie[now].prefix++;//更新前缀数
trie[now].isEnd=true;//这是尾节点
}
inline int searchPrefix(string word) { //查询以这个字符串为前缀的单词数量
int now=0,len=word.size();
if(len<=0) return 0;
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //没这条边,所以不存在这个字符串,更不存在以其为前缀的单词
return false;
}
now=trie[now].next[ch];;
}
return trie[now].prefix;//查询前缀数
}
void Delete(string word) { //删除所有前缀等于给定字符串的单词
int now=0,len=word.size();
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
if(!trie[now].next[ch]) { //没这条边,所以不存在这个字符串,更不存在以其为前缀的单词
return ;
}
now=trie[now].next[ch];
}
trie[now].isEnd=false;
memset(trie[now].next,0,sizeof(trie[now].next));
int t=trie[now].prefix;
trie[now].prefix=0;
now=0;
for(int i=0; i<len; i++) {
int ch=word[i]-'a';
trie[now].prefix-=t;
now=trie[now].next[ch];
}
}
int main() {
int N;
scanf("%d",&N);
string a,b;
int t;
while(N--) {
cin>>a>>b;
if(a=="insert") insert(b);
else if(a=="delete") Delete(b);
else if(a=="search") {
if(searchPrefix(b)) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
}
}
return 0;
}