当前位置: 首页 > article >正文

Trie树(字典树)/(前缀树)

字典树的概念

注意:

(1)在一条边上存字符

(2)如果前缀相同的话,就可以实现复用。

(3)从根节点出发到某个节点的路径就代表一个字符串 

(4)

有->复用
没有->创建

(5)

维护信息:
pass:标记当前节点一共经过多少次
end:b=标记当前节点是以多少个字符串作为结尾
 

 

字典树的实现 

准备工作

 tree[N][26] :里面记录的是 当前的N节点 可以通过字母到达的结点

0号结点可以通过a到达1号结点

#include<iostream>
#include<cstring>

using namespace std;

const int N = 1e6+10;//N表述字符串里面有多少个字符
int tree[N][26];//N表示如上,26表示有26个字母
int p[N];//表示每个结点的出现次数
int e[N];//表示各个字符串的出现次数,记录在叶子结点

int idx;//表示给新来的结点创建

插入操作 

//插入操作
void insert(string& s)
{
    int cur = 0;//表示从根节点出发
    p[cur]++;//根节点经过次数+1
    for(auto ch:s)//遍历字符串
    {
        int path = ch - 'a';//当前字符的当前节点的下标
        if(tree[cur][path] == 0)tree[cur][path] = ++idx;//没有,那就创建一个
        //继续维护,cur 可以根据 ch 来到下标tree[cur][path]
        cur = tree[cur][path];
        p[cur]++;//++
    }
    e[cur]++;//最后的叶子结点++,表示该字符串出现次数+1
}

 

查询操作 

查询前缀 

1.P8306 【模板】字典树 - 洛谷

#include<iostream>
#include<cstring>

using namespace std;

const int N = 3e6 + 10;
int tree[N][62];
int p[N];
int idx = 0;

int get_num(char ch)
{
	if (ch >= 'a' && ch <= 'z')return ch - 'a';
	else if (ch >= 'A' && ch <= 'Z')return ch - 'A' + 26;
	else if (ch >= '0' && ch <= '9')return ch - '0' + 52;
}

void insert(string& s)
{
	int cur = 0;
	p[cur]++;
	for (auto ch : s)
	{
		int path = get_num(ch);
		if (tree[cur][path] == 0)tree[cur][path] = ++idx;

		cur = tree[cur][path];
		p[cur]++;
	}
}

int find_pre(string& s)
{
	int cur = 0;
	for (auto ch : s)
	{
		int path = get_num(ch);
		if (tree[cur][path] == 0)return 0;
		cur = tree[cur][path];
	}
	return p[cur];
}

int T, n, q;
int main()
{
	cin >> T;
	while (T--)
	{
		/*memset(tree, 0, sizeof(tree));
		memset(p, 0, sizeof(p));*///用这个进行清空开销太大
		for (int i = 0; i < idx; i++)
		{
			for (int j = 0; j < 62; j++)
			{
				tree[i][j] = 0;
			}
		}
		for (int i = 0; i < idx; i++)p[i] = 0;
		idx = 0;
		cin >> n>>q;
		while (n--)
		{
			string s; cin >> s;
			insert(s);
		}
		while (q--)
		{
			string pre; cin >> pre;
			cout << find_pre(pre) << endl;
		}
	}
}

 2.P2580 于是他错误的点名开始了 - 洛谷

 

#include<iostream>

using namespace std;
const int N = 5e5 + 10;
//N表示总字符的个数
//== 字符串的个数 * 最大字符串的长度
int e[N];
int tree[N][26];
int idx;

void insert(string& s)
{
	int cur = 0;
	for (auto ch : s)
	{
		int path = ch - 'a';
		if (tree[cur][path] == 0)tree[cur][path] = ++idx;

		cur = tree[cur][path];
	}
	e[cur]++;
}

int find_name(string& s)
{
	int cur = 0;
	for (auto ch : s)
	{
		int path = ch - 'a';
		if (tree[cur][path] == 0)return 0;
		cur = tree[cur][path];
	}
	if (e[cur] > 0)
	{
		e[cur] = -1;
		return 1;
	}
	return e[cur];
}

int n, m;



int main()
{
	cin >> n;
	while (n--)
	{
		string s; cin >> s;
		insert(s);
	}
	cin >> m;
	while (m--)
	{
		string s; cin >> s;
		if (find_name(s) == 1)cout << "OK" << endl;
		else if (find_name(s) == -1)cout << "REPEAT" << endl;
		else cout << "WRONG" << endl;
	}
}
#include<iostream>

using namespace std;
const int N = 5e5 + 10;
//N表示总字符的个数
//== 字符串的个数 * 最大字符串的长度
int e[N];
int tree[N][26];
int idx;

N:表示总字符的个数,总的字符串中一共有多少个字符

3.P10471 最大异或对 The XOR Largest Pair - 洛谷 

贪心,除了最高位是0,其他的全是1那么就是最大的

(1) 利用字典树:先把数字按照0 1 的二进制顺序插如tree中

(2)当来查找时,对于每一个x找除了最高位外,其余二进制位都相反的数字,此时两者异或最大,-->是否存在,

如果存在的话,那就ret  = 0  ,ret |= (1<<1);和对应的二进制位进行异或,记录数据

如果不存在,那就贪不了,只可以按照原来的继续遍历下去

#include<iostream>

using namespace std;

const int N = 1e5 + 10;
int a[N];
int tree[32 * N][2];
int idx;

void insert(int x)
{
	int cur = 0;
	for (int i = 31; i >= 0; i--)//按照二进制位从前向后的顺序插入字典树种
	{
		int path = ((x >> i) & 1);
		if (tree[cur][path] == 0)tree[cur][path] = ++idx;
		cur = tree[cur][path];
	}
}

int find(int x)
{
	int ret = 0;
	int cur = 0;
	for (int i = 31; i >= 0; i--)
	{
		int path = ((x >> i) & 1);
		//当来查找时,对于每一个x找除了最高位外,其余二进制位都相反的数字,此时两者异或最大,-- > 是否存在
		if (tree[cur][path ^ 1])//如果存在的话,那就ret  = 0  ,ret |= (1<<1);和对应的二进制位进行异或,记录数据
		{
			ret |= (1 << i);
			cur = tree[cur][path ^ 1];
		}
		else//如果不存在,那就贪不了,只可以按照原来的继续遍历下去
		{
			cur = tree[cur][path];
		}
	}
	return ret;
}

int main()
{
	int n; cin >> n;
	for (int i = 1; i <= n; i++)
	{
		cin >> a[i];
		insert(a[i]);
	}
	int ret = 0;
	for (int i = 1; i <= n; i++)
	{
		ret = max(ret, find(a[i]));//找每个的最大异或结果
	}
	cout << ret << endl;
	return 0;
}

 


http://www.kler.cn/a/598117.html

相关文章:

  • JVM 学习前置知识
  • 12、Python 异常处理与调试技巧
  • 《Java到Go的平滑转型指南》
  • 轻松认识 SQL 关键字,打开数据库操作大门
  • Java-SpringBootWeb入门、Spring官方脚手架连接不上解决方法
  • 案例:网络命名空间模拟隔离主机场景
  • 人工智能(AI)系统化学习路线
  • Vue 入门到实战 五
  • Java算法队列和栈经常用到的ArrayDeque
  • 刷新页面pinia数据会不会消失
  • 从扩展黎曼泽塔函数构造物质和时空的结构-1
  • 【行驶证识别】批量咕嘎OCR识别行驶证照片复印件图片里的文字信息保存表格或改名字,基于QT和腾讯云api_ocr的实现方式
  • Java 安装开发环境(Mac Apple M1 Pro)
  • 多传感器融合 SLAM LVI-SAM
  • 单链表中的递归算法
  • 【C++教程】bool类型
  • Rust语言的集成测试
  • 数据库数值函数详解
  • 浅谈布隆过滤器(Bloom Filter)
  • 基于CNN-LSTM联合网络的主瓣干扰辨识