代码详解:
#include <iostream>
using namespace std;
const int N = 2e4 + 10;
int son[N][26], cnt[N], idx;
void insert(char str[])
{
int p = 0;
for(int i = 0; str[i]; i++)
{
int u = str[i] - 'a';
if(son[p][u] == 0) son[p][u] = ++idx;
p = son[p][u]; //p = idx;
//trie数中的根节点并不是真实存在的,但是所有存储的字符串的首元素都被存储在二维数组son[N][26]的首元素(一维数组)里面
//既然需要存储的字符串的首元素都存储在二维数组里面的首元素(一维数组)中,那么在一开始存储时,首选的节点就必须是二维数组中首元素的节点,所以一开始p = 0
//在存储过程中,如果发现没有这个节点,就会创建这个节点(son[p][u] = ++idx)
//在创建完这个节点后,p的更改位此时节点的值,p的值始终和idx的值相等,而idx的值是一直++的,不会重复出现
//那么p也不会出现重复,这样就能保证存储下一个节点时,是在另一个一维数组上
//再然后是标记尾节点,存储完字符串,在末尾标进行一个标记
//标记数组只要要是一维数组即可,因为结尾的节点的值等于p,p等于idx,idx不重复,所以每个节点都不会重复,那么只要一个一维数组就可以存储所有不重复的点
}
cnt[p]++; //cnt[idx++];
}
int query(char str[])
{
int p = 0;
for(int i = 0; str[i] != '\0'; i++)
{
int u = str[i] - 'a';
if(son[p][u] == 0) return 0;
p = son[p][u];
//查询也是从二维数组的首元素开始,因为所有字符串的首元素都存储在二维数组得首元素中,所以p = 0
//接下来是判断当前节点是否等于0,如果等于0,就表明当前得节点还没有存储过元素,字符串也就不存在,返回0
//否则一直判断,知道循环结束,那循环结束之后,就要返回当前cnt的p节点的值
//如果这个p节点被标记了(cnt[p] != 0) 那就表明字符串是被存储在了trie树中
}
return cnt[p];
}
int main()
{
int n = 0;
scanf("%d\n", &n);
char op[2], str[N];
while(n--)
{
scanf("%s%s", op, str);
if(op[0] == 'I') insert(str);
else printf("%d\n", query(str));
}
return 0;
}
代码详解:
#include <iostream>
using namespace std;
const int N = 1e5 + 10, M = 31 * N;
//输入的数据次数不超过1e5,而每个数的范围不超过2^31
//在字典树(Trie树)中,存储每个数是以二进制的形式存储的,每个节点存储这个数的二进制值
//那么以二进制的形式存储1e5个数,最多需要31*1e5个节点
int a[N], son[M][2], idx;
//字典树是一个二维数组,里面的元素是一维数组
//而一维数组的元素下标则是需要存储的字母或这二进制数的种类,所以这里只需要一个长度为2的一维数组即可
//这也从侧面说明当得知字母或者二进制后,我们会这样标记一个节点son[p][u];u是二进制或这字母的ASCII值
//关于插入操作:
void insert(int& x)
{
int p = 0;
for(int i = 30; i >= 0; i--)
{
int u = (x >> i) & 1;
if(son[p][u] == 0) son[p][u] = ++idx;
p = son[p][u];
//关于这里的存储操作:
//按照平时读数据的操作,从左往右读,所以依次求出x的第31位到第1位的二进制表示
//接下来判断当前son[p][u]节点是否存在,如果不存在,就创建出这个节点
}
}
//关于异或操作:
int search(int& x)
{
int p = 0, res = 0;
for(int i = 30; i >= 0; i--)
{
int u = (x >> i) & 1;
if(son[p][!u] != 0)
{
res += 1 << i;
p = son[p][!u];
//查询操作:
//对于x的某一位二进制,我们需要找到相反数才能让这一位异或得到1,使其最大,
//但假如说这个相反的点不存在,那就只能找到标记点,继续下去
//每次找到一个相反的数,就能在相应的位得到一个1,那么只需要让res加上1左移相应的位数即可
}
else p = son[p][u];
}
return res;
}
int main()
{
int n = 0, res = 0;
scanf("%d\n", &n);
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
insert(a[i]);
}
for(int i = 0; i < n; i++) res = max(res, search(a[i]));
printf("%d\n", res);
return 0;
}