「2024 - 暑假 - Day-2 提高笔记-字典树」
1.CSP考前2.「Day 1—递归问题」3.「Day 2—贪心问题&分治&前缀和」4.「Day 3—深度优先搜索 & 广度优先搜索」5.「Day 4—图的存储 & 图上搜索」6.「Day 5—最短路径」7.「Day 6—单调栈 & 单调队列 & 并查集」8.「Day 7—离散化 & 树状数组 & 线段树」9.「Day 8—最小生成树之Kruskal & Prim」10.「Day 9 & 10—DP问题」11.「Day 11 & 12 & 13 & 14—杂项」12.「2024 - 暑假 - Day-1 提高笔记-割点(割边)」
13.「2024 - 暑假 - Day-2 提高笔记-字典树」
14.【基础知识】15.「2024 - 暑假 - Day-3 提高笔记-ST表 & RMQ」16.「2024 - 暑假 - Day-4 提高笔记-LCA最近公共祖先」17.「2025 - 寒假 - Day-2 提高笔记-反悔贪心」字典树
字典树是什么?
理论知识
- 插入操作
我们在插入的时候,先从根节点去向下遍历。对于字符串
- 如果发现其在字典树中当前节点下有这个字符
,则继续向下,在向下的过程中每次给当前节点的次数加 ,记录字符串前缀数量。 - 若无这个字符,则开辟一个新的节点,记录节点编号,继续向下。
- 查询前缀数量
我们在查询前缀的时候,先从根节点去向下遍历。对于字符串
- 若在字典树当前节点下没有
,则证明没有以该前缀为开头的单词。 - 否则就继续向下,直到
,最后返回该节点数下的前缀数量。
时间复杂度
对于一个长度为
代码实现
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 3e6 + 5;
int T;
int n,q;
char s[MAXN];
int ch[MAXN][100],cnt[MAXN],id = 0;
int got(char c){
if(c >= 'A' && c <= 'Z') return c - 'A';
if(c >= 'a' && c <= 'z') return c - 'a' + 26;
return c - '0' + 52;
}
void Insert(char *s){
int now = 0;
for(int i = 0;s[i];i ++){
int v = got(s[i]);
if(!ch[now][v]){
ch[now][v] = ++ id;
}
now = ch[now][v];
cnt[now] ++;
}
return;
}
int query(char *s){
int now = 0;
for(int i = 0;s[i];i ++){
int v = got(s[i]);
if(!ch[now][v]) return 0;
now = ch[now][v];
}
return cnt[now];
}
void Clear(){
memset(ch, 0, sizeof(ch[0]) * (id + 1));
memset(cnt, 0, sizeof(cnt[0]) * (id + 1));
id = 0;
}
signed main(){
scanf("%d",&T);
while(T --){
scanf("%d%d",&n,&q);
for(int i = 1;i <= n;i ++){
scanf("%s",s);
Insert(s);
}
for(int i = 1;i <= q;i ++){
scanf("%s",s);
cout << query(s) << '\n';
}
Clear();
}
return 0;
}
例题
P1481 魔族密码
这个题最开始我没想到怎么写,后来就发现,我们只要暴力
#include<iostream>
using namespace std;
const int MAXN = 3 * 1e4 + 5;
int ans = 0;
int n,q;
char s[MAXN];
bool isend[MAXN];
int ch[MAXN][100],cnt[MAXN],id = 0;
void Insert(char *s){
int now = 0;
for(int i = 0;s[i];i ++){
int v = s[i] - 'a';
if(!ch[now][v]){
ch[now][v] = ++ id;
}
now = ch[now][v];
cnt[now] ++;
}
isend[now] = 1;
return;
}
void dfs(int p,int step){
step += isend[p];
bool back = 1;
for(int i = 0;i < 26;i ++){
if(ch[p][i] != 0){
dfs(ch[p][i],step);
back = 0;
}
}
if(back == true){
ans = max(ans,step);
}
}
signed main(){
scanf("%d",&n);
for(int i = 1;i <= n;i ++){
scanf("%s",s);
Insert(s);
}
dfs(0,0);
cout << ans << '\n';
return 0;
}
本文来自一名初中牲,作者:To_Carpe_Diem
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探