trie树

trie树

【例题】

洛谷P2580 于是他错误的点名开始了
题目大意:给出n个单词,有m个询问,每次给出一个单词,如果这个单词出现过且是第一次出现,输出“OK”,如果这个单词没有出现过,输出“WRONG”,如果这个单词出现过但不是第一次出现,输出“REPEAT”,其中n≤10000,m≤100000,每个单词长度l≤50。

【定义】

根节点不包含字符,除根节点外每一个节点都只包含一个字符
从根节点到某一节点,路径上经过的字符连接起来,为该节点对应的字符串
每个节点的所有子节点包含的字符都不相同

【介绍】

是一种树形结构,是一种哈希树的变种。典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串),所以经常被搜索引擎系统用于文本词频统计。它的优点是:利用字符串的公共前缀来减少查询时间,最大限度地减少无谓的字符串比较,查询效率比哈希树高。(来自:百度)

【方法】

假设是这样的一棵trie树。

插入:

现在有一个字符串s 需要加入这棵trie树。
那么我们要一个一个字符去判断,如果有这个节点,就共享,否则就重新创建一个新的节点。

代码:

void build(int len,int p)
{
	for(int i=0;i<len;i++)
	{
		if(a[p][s[i]-'a'+1]==0) a[p][s[i]-'a'+1]=++t;
		p=a[p][s[i]-'a'+1];
	}
}

所以加入的时间复杂度应该是: O ( l e n ) O(len) O(len)

查找:

现在需要查找字符串s是否存在于这棵trie树中。
那么我们可以在这棵trie树上一个一个字符查找,如果找不到就退出。

代码:

void query(int len,int p)
{
	for(int i=0;i<len;i++)
	{
		if(a[p][s[i]-'a'+1]==0)
		{
			ans=0;
			return;
		}
		p1=p;
		p=a[p][s[i]-'a'+1];
	}
	if(b[p1][s[len]-'a'+1]>0) return;
	b[p1][s[len]-'a'+1]++;
	ans=1;
	return;
}

所以查找的时间复杂度应该是 O ( l e n ) O(len) O(len)

洛谷P2580 于是他错误的点名开始了完整代码:

#include<bits/stdc++.h>
using namespace std;
char s[55];
int a[1000005][27],b[1000005][27],t,ans,n,p1;
void build(int len,int p)
{
	for(int i=0;i<len;i++)
	{
		if(a[p][s[i]-'a'+1]==0) a[p][s[i]-'a'+1]=++t;
		p=a[p][s[i]-'a'+1];
	}
}
void query(int len,int p)
{
	for(int i=0;i<len;i++)
	{
		if(a[p][s[i]-'a'+1]==0)
		{
			ans=0;
			return;
		}
		p1=p;
		p=a[p][s[i]-'a'+1];
	}
	if(b[p1][s[len]-'a'+1]>0) return;
	b[p1][s[len]-'a'+1]++;
	ans=1;
	return;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%s",&s);
		build(strlen(s),0);
	}
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		ans=-1;
		scanf("%s",&s);
		query(strlen(s),0);
		if(ans==-1) printf("REPEAT\n");
		else if(ans==0) printf("WRONG\n");
		else printf("OK\n");
	}
	return 0;
}
posted @   2020fengziyang  阅读(11)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
· 使用C#创建一个MCP客户端
点击右上角即可分享
微信分享提示