HDU - 5687 Problem C(字典树的添加,查询,删除)

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();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值