算法学习专栏——Tire算法
前言:字典树(Tire)
定义
Tire是一种能够快速插入和查询字符串的多叉树结构
根结点编号为0,初始位置,不存任何东西。
其他节点:
1.标记路径
2.记录单词插入次数
边: 表示字符
Tire维护字符串集合,支持两种操作
*void insert(char s): 向集合插入一个字符串
*void query(char s): 在集合中查询一个字符串
建字典树
下面我们就可以准备代码编写需要的数组了:
节点编号idx:
用来记录节点
儿子数组 son[p] [i]:
存储从节点p沿着这条边走到的子节点编号,比如上图的节点1,对应表示的就是从1节点沿着d边可以走到节点4。
而这里的边(i)为26个字符**(a
z)对应的映射值025,每个节点最多可以有26个分支,例如上面图中的:son[0] [3] = 1;son[1] [14] = 2;son[1] [3] = 4……**记录数组:
存储的是以当前节点p为结尾的插入字符串个数
插入操作
1.空 Tire 仅有1个根结点,编号为0 ;
2.从根开始插,枚举字符串的每个字符,如果有儿子(也就是子节点),则p指针走到儿子如果没有儿子,则先创建儿子,p指针再走到儿子;反之则直接走向儿子
3.在单词结束点记录插入次数,也就是cnt[p]++
1 | |
查询操作
1.从根开始查,扫描字符串
2.有字母**s[i]**,则走下去,能走到词尾,则返回插入次数
3.无字母s[i],则返回0
1 | |
一、Tire字符串统计(简单+)
维护一个字符串集合,支持两种操作:
I x向集合中插入一个字符串 x;Q x询问一个字符串在集合中出现了多少次。
共有 N 个操作,所有输入的字符串总长度不超过 10^5^,字符串仅包含小写英文字母。
输入格式
第一行包含整数 N,表示操作数。
接下来 N 行,每行包含一个操作指令,指令为 I x 或 Q x 中的一种。
输出格式
对于每个询问指令 Q x,都要输出一个整数作为结果,表示 x 在集合中出现的次数。
每个结果占一行。
数据范围
1≤N≤2∗104
输入样例:
1 | |
输出样例:
1 | |
思路
直播讲解(会录屏)
代码
答案(请自己先思考一下再参考)
#include < iostream>
#include < algorithm>
using namespace std;
const int N = 1e5 + 10;
int a[N][26];
char s[N];
int cnt[N];
int n, idx;
void insert(char s[]) {
int p = 0;
for (int i = 0; s[i]; i++) {
int u = s[i] - 'a';
if (!a[p][u]) a[p][u] = ++idx;
p = a[p][u];
}
cnt[p] ++;
}
int query(char s[]) {
int p = 0;
for (int i = 0; s[i]; i++) {
int u = s[i] - 'a';
if (!a[p][u]) return 0;
p = a[p][u];
}
return cnt[p];
}
int main()
{
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
cin >> n;
for (int i = 0; i < n; i++) {
char op[2];
cin >> op >> s;
if (op[0] == 'I') {
insert(s);
} else {
cout << query(s) << '\n';
}
}
return 0;
}
二、最大异或对(简单++)
在给定的 N 个整数 A1,A2……AN 中选出两个进行 xor(异或)运算,得到的结果最大是多少?
输入格式
第一行输入一个整数 N。
第二行输入 N 个整数 A1~AN。
输出格式
输出一个整数表示答案。
数据范围
1 ≤N ≤10^5^
0 ≤Ai <2^31^
输入样例:
1 | |
输出样例:
1 | |
思路
直播讲解(录屏)
代码
1 | |