LINK
度熊手上有一本神奇的字典,你可以在它里面做如下三个操作:
1、insert : 往神奇字典中插入一个单词
2、delete: 在神奇字典中删除所有前缀等于给定字符串的单词
3、search: 查询是否在神奇字典中有一个字符串的前缀等于给定的字符串
Input
这里仅有一组测试数据。第一行输入一个正整数N (1\leq N\leq 100000)N(1≤N≤100000),代表度熊对于字典的操作次数,接下来NN行,每行包含两个字符串,中间中用空格隔开。第一个字符串代表了相关的操作(包括: insert, delete 或者 search)。第二个字符串代表了相关操作后指定的那个字符串,第二个字符串的长度不会超过30。第二个字符串仅由小写字母组成。
Output
对于每一个search 操作,如果在度熊的字典中存在给定的字符串为前缀的单词,则输出Yes 否则输出 No。
Sample Input
5
insert hello
insert hehe
search h
delete he
search hello
Sample Output
Yes
No
- 分析:坑点:不要只处理删除字符串的最后一个字母,如果查询前缀的前几个字母依然可以查到。
所以每个点都记录进入次数,如果删除字符串,次数也要减一。
ac代码:
#include<stdio.h>
#include<algorithm>
#include<string.h>
typedef long long ll;
using namespace std;
int idx;
char a[40],f[20];
int book[3000010][30],cnt[3000010];
void insert()
{
int p=0,i;
for(i=0;a[i];i++)
{
int u=a[i]-'a';
if(!book[p][u])
book[p][u]=++idx;
p=book[p][u];
cnt[p]++;//记录树点出现的次数。
}
}
int query()
{
int i,p=0,u,l;
l=strlen(a);
for(i=0;i<l;i++)
{
u=a[i]-'a';
if(!book[p][u])
return 0;
p=book[p][u];
}
if(i==l&&cnt[p])//如果没有含有这个前缀的字符串了 cnt[p]=0;
return 1;
}
void del()
{
int i,p,l,u,ans;
p=0;
l=strlen(a);
for(i=0;i<l;i++)
{
u=a[i]-'a';
if(book[p][u])
p=book[p][u];
else return;
}
ans=cnt[p];
p=0;
for(i=0;i<l;i++)
{
u=a[i]-'a';
p=book[p][u];
cnt[p]-=ans;//必须减去出现次数,为了上边的注释内容。
}
for(i=0;i<26;i++)
book[p][i]=0;//前缀没了,该点(前缀尾巴)后面的分支都不存在了,变0后都搜不到了
}
int main()
{
int i,n;
scanf("%d",&n);
for(i=0;i<n;i++)
{
scanf("%s",f);
scanf("%s",a);
if(f[0]=='i')
insert();
else if(f[0]=='s')
{
if(query())
printf("Yes\n");
else printf("No\n");
}
else if(f[0]=='d')
del();
}
}