字典树(Tire树)C++详解,一文让你理解字典树
问题引入
现在,我给你n个单词,然后进行q次询问,每一次询问一个单词b,问你b是否出现在n个单词中,你会如何去求呢?
暴力搜索?但是我们如果这么做的话时间复杂度一下就高上去了。大家都是成熟的ACMer了,不要再惦记着暴力的方法啦,要优雅。
你想想,问题的描述像不像查字典的操作?你平时是怎么查字典的?想想看?
如果你要在字典中查找单词“Avalon”,你是不是先找到首字母为‘A’的部分,然后再找第二个单词为‘V’的部分······最后,你可能可以找到这个单词,当然,也有可能这本词典并没有这个单词。
你想想看,你这样子的查单词的方式是不是比你从词典第一页开始查询到最后一页寻找单词“Avalon”要高效多了?那我们可不可以也建一本"字典"呢?
字典树介绍
概念:字典树(TrieTree),是一种树形结构,典型应用是用于统计,排序和保存大量的字符串(但不仅限于字符串,如01字典树)。主要思想是利用字符串的公共前缀来节约存储空间。很好地利用了串的公共前缀,节约了存储空间。字典树主要包含两种操作,插入和查找。
比如,我们要怎么用树存下单词"abc",“abb”,“bca”,"bc"呢?如图
在图中,红点代表有一个以此节点为终点的单词。然后,我们如果要查找某个单词如s=“abc”,就可以这样
在这里,s=“abc” 的每一个字母都在树中被查到了,并且最后一个点是红色代表有一个在此结束的单词,查询成功。而 s=“bb” 的第二个字母没有在相应位置被查到,因此"bb"不在字典中。至于s=“ab” 虽然单词中每个点都被查到了,但是由于结尾的字母在树中没有标红,因此也是不在字典中。
对于字典树的每次查找,时间复杂度为log级别,比暴力快多了。
字典树代码实现方法
在用代码实现字典树时,我们主要需要实现两种操作:即录入单词和查找单词,这里我们用两个函数来实现,然后我们用一个二维数组来实现字典树的建树。先把代码写出来,之后再解释。
模板如下:
const int N = 1000050;
int trie[N][26];
int cnt[N];
int id;void insert(string s)
{int p = 0;for (int i = 0; i < s.size(); i++){int x = s[i] - 'a';if (trie[p][x] == 0) trie[p][x] = ++id;p = trie[p][x];}cnt[p]++;
}int find(string s)
{int p = 0;for (int i = 0; i < s.size(); i++){int x = s[i] - 'a';if (trie[p][x] == 0)return 0;p = trie[p][x];}return cnt[p];
}
这里我们用到了几个变量,这里分别一一解释
1.变量id: id代表字典树中每一个节点的编号,id的大小只与插入字典树的先后顺序有关,它的作用在下面会讲到。
2.trie[N][26]: 每个trie代表一条边,字典树其中1~N为边上方节点的编号,0代表root节点,1~26为连在i节点下方的26个字母。如果trie[i][x]=0,则代表字典树中目前没有这个点,而trie[i][x]的值代表这个点下方连有的点的编号,例如:trie[i][3]=9代表第i号点和的下方连有一个点‘c’,并且那个点的编号是9,为什么是c呢?因为 ‘c’-‘a’=2
3.cnt[N]: cnt[i]==0代表编号为i的点不是一个单词的结束点,在上面的图中代表这个点不是空点,但是没有标红,cnt[i]!=0代表编号为i的点是一个单词的结束点,即红点。cnt[i]不一定只为0或1,因为有可能多次输入了同一个单词。
4.(难点)两个函数中的变量p:
p代表查询与插入时的不断变化的当前节点编号,初始化为0,代表初始节点,在函数的循环中,我们首先用x确定接下来要找的字母,再通过变量x确定了接下来我们需要查找当前节点下是否有连接着目标字母的节点。通过每次确定的x,我们通过trie[p][x] 查找连着目标字母的节点的编号,如果目标节点存在,就把p更新成目标节点的编号(p = trie[p][x])。而如果trie[p][x] == 0,代表字典树中没有这个点,如果是查找就代表没有这个单词,查找失败。而如果是插入函数,我们就用 ++id 来把这个点存进字典树。我们在两个函数的最后用cnt[p]来涂红节点或返回节点值。
我们先后插入单词"abc",“abb”,“bca”,“bc”,那编号就是这样。
trie[上节点编号][下方连接的字母]=下方连接的字母的节点编号
trie[0][0]=1;trie[0][1]=5;
trie[1][1]=2;
trie[2][1]=4;trie[2][2]=3;
trie[5][2]=6;
trie[6][0]=7;
其余trie[i][j]都为0,即空节点;
cnt[4]=cnt[3]=cnt[6]=cnt[7]=1;
如果我再往字典树中插入"bcd",字典树就更新为
新增
trie[6][3]=8;cnt[8]=1
让我们试着查询看看"abc"与"bb"
最后,我们查到了"abc",但没查到"bb"
例题:
问题 B: 【一本通提高篇Trie字典树】The XOR Largest Pair
[题目描述]
给定的n个整数A1,A2,A3......An中选出两个进行异或运算,最后最大结果是多少
输入
第一行一个整数N
第二行N个整数Ai
输出
一个最大结果
样例输入
5 2 9 5 7 0
样例输出
14
算法分析
如果用暴力的方法,枚举所有情况,时间复杂度为O ( N 2 ) O(N^2)O(N
2 )
进行X O R XORXOR运算时,从高位到低位,如果为1 11,则让0 00和其匹配,如果为0 00,则让1 11和其匹配。
可以将N NN个数转换为字典树,枚举每一个数,根据其二进制在字典树中查找与其匹配的最大异或值,枚举N NN个数为O ( N ) O(N)O(N),字典树最大深度为31 3131,总时间复杂度为O ( 31 N ) O(31N)O(31N)。
代码如下:
#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
const int N = 101000, M = 31 * N;
int son[M][2], a[N];
int idx;
int n, ans = -1;void insert(int x)
{int p = 0;for(int i = 31; i >= 0; i--){int u = (x >> i) & 1;if(!son[p][u]) son[p][u] = ++idx;p = son[p][u];}
}int query(int x)
{int p = 0, res = 0;for(int i = 31; i >= 0; i--){int u = (x >> i) & 1;if(son[p][!u]){p = son[p][!u];res = res * 2 + !u;}else{p = son[p][u];res = res * 2 + u;}}res = res ^ x;return res;
}
int main()
{scanf("%d", &n);for(int i = 1; i <= n; i++){scanf("%d", &a[i]);insert(a[i]);ans = max(ans, query(a[i]));}printf("%d", ans);return 0;
}
字典树(Tire树)C++详解,一文让你理解字典树相关推荐
- 托福字典:progressively托福考试详解
progressively是什么意思?progressively这个托福词汇在托福考试TPO中考题出现在了OG和TPO44当中,是什么意思呢?本文美联出国考试小编给大家整理了托福字典:progress ...
- 常见字典用法集锦及代码详解
目录 前言 字典的简介 1. 字典对象 1.1 Add 方法 1.2 Exists 方法 1.3 Keys 方法 1.4 Items 方法 1.5 Remove 方法 1.6 RemoveAll 方法 ...
- python读取json格式文件大量数据,以及python字典和列表嵌套用法详解
1.Python读取JSON报错:JSONDecodeError:Extra data:line 2 column 1 错误原因: JSON数据中数据存在多行,在读取数据时,不能够单单用open(), ...
- 7-1 修理牧场 (25 分)(最详解)(最容易理解的解题过程)
7-1 修理牧场 (25 分)(最详解)(最容易理解的解题过程) 农夫要修理牧场的一段栅栏,他测量了栅栏,发现需要N块木头,每块木头长度为整数Li个长度单位,于是他购买了一条很长的.能锯成N块的 ...
- flex+php ria应用开发实战详解光盘,《Flex+PHPRIA应用开发实战详解-梁文新版》学习日记2...
这本书真是折磨啊,今天看到了XML解析部分,文章在介绍函数及其参数时很是仔细,但是这本没有把源码最终写清楚,总是少一部分,xml和php对大小写不是很敏感,均能读出来,今天也遇到一个乱码问题,希望这方 ...
- flex+php ria应用开发实战详解,《Flex+PHP RIA应用开发实战详解-梁文新版》学习日记2...
这本书真是折磨啊,今天看到了XML解析部分,文章在介绍函数及其参数时很是仔细,但是这本没有把源码最终写清楚,总是少一部分,xml和php对大小写不是很敏感,均能读出来,今天也遇到一个乱码问题,希望这方 ...
- 标准差详解-一文搞懂标准差的含义
标准差详解-一文搞懂标准差的含义 转载自 样本标准差的意义是什么? 的第一个回答
- mysql联合索引B 树_B+树和Mysql索引详解
B+树总结 根据以下几篇文章总结的自己的心得,便于自己理解 B+树内部平衡详解 B+树存储原理 B+树存储 MySQL索引-B+树(看完你就明白了) 从B树.B+树.B*树谈到R 树 我们一般看到的B ...
- CART分类决策树、回归树和模型树算法详解及Python实现
机器学习经典算法详解及Python实现–CART分类决策树.回归树和模型树 摘要: Classification And Regression Tree(CART)是一种很重要的机器学习算法,既可以用 ...
最新文章
- 搜索Idiot就出现特朗普图片,算法无罪!
- CentOS7升级JDK
- 要锻炼二手交换的能力
- yum mysql_yum安装mysql
- Django+Echarts画图实例
- Manacher入门
- 【资料整理】squid安装和配置代理上网
- pytorch forward
- 服务器外置硬盘安装教程,小容量Mac用户必看——苹果电脑外接硬盘安装windows教程...
- Kafka权威指南-学习笔记---第一章
- K3wise数据字典及常用表及视图
- 藏在耳机里的小东西——蓝牙天线
- 猿创征文 | 国产数据库之神通数据库详解安装和使用
- 亿图图示专家 ((EDraw Max)V5.6 绿色特别版
- 复化科特斯公式matlab_牛顿
- vue轻量级后台管理系统基础模板
- 用Android 写生成的梅花
- 凸包Graham算法
- C语言求组合数C35,巧用组合数的性质求和
- FULLTEXT 搜索