目录
Trie的作用:高效的存储和查找字符串
建立Trie树
例如:给定若干各字符串,建立一个Trie树。不妨设这个字符串是由小写字母组成的。
初始化
int son[N][26], idx;
ps:son数组表示Trie树的儿子结点,N表示需要建立的字符串的数量,m表示每一个字符串的不同字母。idx表示待使用的son数组下标,从0开始
插入
void insert(char* str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!son[p][u]) son[p][u] = ++idx; // 当son数组中没有该字母,那么就开辟一个空间,对应的代码就是++idx
p = son[p][u];
// 还可以使用下面代码实现上面代码
//int& s = son[p][str[i] - 'a']; s为引用
//if(!s) s = ++idx;
//p = s;
}
//cnt[p]++;
}
在每一个字符串结束的后面可以添加一个标记,这个标记可以使用一个cnt数组来表示。
当遍历这个Trie树时,对应下标cnt数组不为空,那么则表示这存在一个字符串
询问该字符串出现的次数
int query(char* str)
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(!son[p][u]) return 0;
p = son[p][u];
}
return cnt[p];
}
求数组中任意两个数异或的最大值
这个题目可以使用Trie树,根据异或的性质,求一个数和另一个数异或的最大值,要求二进制每一位都不相同。
- 先将数组的每一个数以二进制的形式存储到Trie树中
- 固定一个数,根据异或要求,寻找Trie树中每一位不相同
建Trie树
void insert(int x)
{
int p = 0;
// 根据数的范围2^31,当i = -1时,存储的是-1的补码,1…………111,取反就是0
for(int i = 30; ~i; i--)
{
int s = x >> i & 1; // s表示x的每一位是0或1
if(!son[p][s]) son[p][s] = ++idx; // 当不存在这个数,就开辟新空间,++idx
p = son[p][s];
// 当然下面代码和上面是等价的
//int &s = son[p][x >> i & 1];
//if(!s) s = ++idx;
//p = s;
}
}
寻找一个数的最大异或值
int query(int x)
{
int p = 0;
int res = 0;
for(int i = 30; ~i; i--)
{
int s = x >> i & 1;
if(son[p][!s]) // 根据异或的性质,当s = 0 时,需要寻找1;当s = 1 时,需要寻找0
{
// 找到了,那么结果的二进制对应的第i位为1
res += 1 << i;
p = son[p][!s];
}
else p = son[p][s]; // 没找到,那么结果的二进制对应的第i位为0
}
return res;
}