在计算机科学中,trie,又称前缀树或字典树,是一种有序树,用于保存关联数组,其中的键通常是字符串。
Trie树可以用于高效的存储字符串集合,并且可以很快的查找某个字符串是否在集合中出现过或在集合中出现的次数。
Trie树的基本性质 (1)根节点不包含字符,除了根节点之外,每个节点包含一个字符 (2)根节点到一个子节点为这个子节点所存储的字符串 (3)每个节点的所有子节点连接起来的字符串各不相同
下面我们来说一下这道题如何去实现
(题目中的数据范为2*10^5 , 定义const int N = 1e5 + 10 , 1e5为科学计数法,+10是为了保险起见) 首先我们需要使用一个二维数组 son[N][26] 来存储我们的Trie树,因为只有小写英文字母26个,所以第二维度的大小定义为26即可。
我们还需要一个唯一的变量 idx 来存储我们的节点。
在存储完一个字符串的时候,取到他的唯一的下标 idx , 用一个一维数组来记录这个字符串出现的次数。
下面就来看一下是如何实现的把。
维护一个字符串集合,支持两种操作:
“I x”向集合中插入一个字符串x;“Q x”询问一个字符串在集合中出现了多少次。共有N个操作,输入的字符串总长度不超过 105105,字符串仅包含小写英文字母。
第一行包含整数N,表示操作数。
接下来N行,每行包含一个操作指令,指令为”I x”或”Q x”中的一种。
对于每个询问指令”Q x”,都要输出一个整数作为结果,表示x在集合中出现的次数。
每个结果占一行。
1≤N≤2∗1041≤N≤2∗104
在给定的N个整数A1,A2……ANA1,A2……AN中选出两个进行xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数N。
第二行输入N个整数A1A1~ANAN。
输出格式
输出一个整数表示答案。
数据范围
1≤N≤1051≤N≤105, 0≤Ai<2310≤Ai<231
输入样例:
3 1 2 3输出样例:
3 #include <iostream> using namespace std; const int N = 1e5 + 10 , M = 3e6 + 10; int n , a[N] , son[M][2] , idx; // 向 Trie树 中插入数据 void insert(int x) { int p = 0; // int类型数据有32位,最高位是符号位,所以数据位有31位 // 要求出最大的异或对,所以从最高位开始计算 for(int i = 30 ; i >= 0 ; i--) { // x >> i & 1 可以求出 x 的第i位是1或0 int &s = son[p][x >> i & 1]; if(!s) s = ++idx; p = s; } } int search(int x) { int p = 0 , res = 0; for(int i = 30 ; i >= 0 ; i--) { int s = x >> i & 1; // 求异或, 0 和 1 异或值才最大,所以如果第i位是1的话,优先去判断0的位置是否有值 if(son[p][!s]) { // 将值向左移 i 位之后,使用res记录下来 res += 1 << i; p = son[p][!s]; }else { p = son[p][s]; } } return res; } int main() { scanf("%d" , &n); for(int i = 0 ; i < n ; i++) { scanf("%d" , &a[i]); insert(a[i]); } int res = 0; for(int i = 0 ; i < n ; i++) res = max(res , search(a[i])); printf("%d" , res); }