当前位置: 首页 > news >正文

蓝桥杯b组c++赛道---字典树

一. 字典树(Trie 树)基础概念

字典树是一种树形结构,用于高效地存储和检索字符串数据集 中的键,也叫前缀树。它的每个节点代表一个字符,从根节点到某一节点的路径上的字符连接起来,就形成了一个字符串前缀。比如存储字符串 “apple”“app”“banana”,“app” 这部分路径是共享的。

二. 字典树在 C++ 中的实现

以下是在 C++ 中实现字典树的关键部分:

定义数据结构

const int N = 1e5 + 10;
int ch[N][26], cnt[N], idx; 
// ch表示树,ch[p][j] 表示存储从节点p沿j这条边走到下一子节点(j 取值 0 - 25 对应26个英文字母)
// 计数数组cnt[p] 存储以节点p结尾的单词的插入计数
// 节点编号idx,用来给新节点编号

插入字符串函数:

void insert(char *s) {int p = 0;for (int i = 0; s[i]; i++) {int j = s[i] - 'a'; // 映射26位字母到0~25if (!ch[p][j]) ch[p][j] = ++idx; // 建立第一次在p节点遇见的字母的分支p = ch[p][j]; // 更新p到下一层}cnt[p]++; // 到达字符串末尾,该节点计数加1
}

这里从根节点开始,依次处理字符串的每个字符,若对应子节点不存在就创建,最后将字符串结束位置的节点计数加 1 。

查询函数

int query(char *s) {int p = 0;for (int i = 0; s[i]; i++) {int j = s[i] - 'a';if (!ch[p][j]) return 0; // 没有找到对应分支,说明字符串没插入过p = ch[p][j];}return cnt[p]; // 返回以该字符串结尾的插入次数
}

该函数用于判断某个字符串在字典树中的出现次数是否大于 0 ,沿着字符串字符对应的分支走,若途中分支不存在则返回 0,走到末尾返回对应节点的计数。

三. 字典树在蓝桥杯 B 组 C++ 赛道的应用场景

字符串前缀匹配问题

比如题目中给出大量单词,让你统计有多少单词以某个特定前缀开头。通过字典树,插入所有单词后,用查询函数就能快速得到结果。例如有单词 “apple”“app”“apply”,查询 “ap” 前缀,就能通过字典树高效得出有 3 个 。

字符串去重与计数

在插入字符串时,通过节点计数,可以统计每个字符串出现的次数,同时也能实现去重功能。比如统计一篇文章中每个单词出现的频率,就可以将单词依次插入字典树,最后看每个单词对应节点的计数 。

四、示例题目及分析:

小蓝的神秘图书馆
问题描述
小蓝是图书馆的管理员,他负责管理图书馆的所有书籍。
图书馆有 N 本书,每本书都有名字,分别为 S1,S2,...,SN。
图书馆的读者们经常来询问小蓝,他们会给小蓝一个字符串T,
希望小蓝能告诉他们,图书馆里有多少本书的名字是以 T 的前缀开头的。
小蓝需要回答他们 M次 这样的询问。
现在,小蓝需要你的帮助。你能帮助小蓝解决这个问题,从而提升图书馆的服务质量书馆的服务质量吗?

解题思路

本题可使用字典树(Trie 树)来解决,以下是具体思路:

构建字典树
  1. 定义字典树的数据结构:
    • 用一个二维数组 son 来表示字典树的节点关系,son[i][j] 表示节点 i 的字符 j 对应的子节点(这里 j 可通过字符减去 'a' 映射到 0 - 25 的整数,用于表示 26 个英文字母)。
    • 用一个数组 cnt 记录每个节点被经过的次数,即有多少字符串以该节点为前缀。
    • 用一个变量 TOT 记录当前字典树中使用的节点总数。
  2. 插入操作:
    • 遍历每本书的名字字符串。从字典树的根节点(编号为 0 )开始,对于字符串中的每个字符,将其转换为 0 - 25 的索引值(u = S[i] - 'a' )。
    • 检查当前节点是否存在该字符对应的子节点,如果不存在则创建一个新节点(son[q][u] = ++TOT ),并将当前节点移动到该子节点(q = son[q][u] )。
    • 每经过一个节点,将该节点的计数加 1(cnt[q]++ ),表示有一个字符串经过了此节点。
查询操作
  1. 对于每个查询字符串 T ,同样从根节点开始。
  2. 遍历查询字符串的每个字符,将字符转换为索引值并沿着字典树的对应分支移动。
  3. 如果在移动过程中遇到某个字符对应的子节点不存在(son[q][u] == 0 ),说明不存在以该查询字符串为前缀的书籍名字,直接返回当前的计数(此时计数为 0 )。
  4. 如果顺利遍历完查询字符串,那么此时所在节点的 cnt 值就是以该查询字符串为前缀的书籍名字的数量,返回这个值。
整体流程
  1. 读取书籍数量 N 和查询次数 M 。
  2. 循环 N 次,读取每本书的名字并插入到字典树中。
  3. 循环 M 次,读取每个查询字符串,调用查询函数得到结果并输出
#include<bits/stdc++.h>
using namespace std;const int N=2e5+10;//N: 最大节点数的估计值
int n,q,cnt[N*27],son[N][27],TOT=0;
//n: 插入的字符串数量
//q: 查询的次数
//cnt[]: 记录每个节点被访问的次数(即有多少字符串以该节点为前缀)
//son[][]: 字典树的子节点数组,son[u][c] 表示节点 u 的字符 c 对应的子节点
//TOT: 当前使用的节点总数//构造前缀树
void insert(string S) {int q=0;for(int i=0; i<S.size(); i++) {int u=S[i]-'a';//映射,把字符转为数字索引if(son[q][u] == 0)//检查当前节点 q 是否存在字符 u 对应的子节点。son[q][u]=++TOT;// 创建新节点并分配唯一编号。q=son[q][u];cnt[q]++;}
}//匹配子串 
int query(string T){int q=0,ans=0;for(int i=0;i<T.size();i++){int u=T[i]-'a';q=son[q][u];if(q==0)return ans;//没找到}return cnt[q];
}int main() {cin>>n>>q;string s;for(int i=1; i<=n; i++) {cin>>s,insert(s);}for(int i=1; i<=q; i++) {cin>>s,cout<<query(s)<<'\n';}return 0;
}

相关文章:

  • IPv4地址的主要配置项介绍
  • 语音识别算法的性能要求一般是多少
  • 基于多流特征融合与领域知识整合的CNN-xLSTM-xAtt网络用于光电容积脉搏波信号的无创血压估计【代码已复现】
  • Matlab中gcb、gcbh、gcs的区别
  • Cursor 与DeepSeek的完美契合
  • 实时同步缓存,与阶段性同步缓存——补充理解《补充》
  • OpenCV 图像像素的读写操作
  • leetcode hot100刷题日记——18.搜索插入位置
  • PCB设计自检表
  • SAAS架构设计2-流程图-注册流程图
  • 【premiere教程】【01】【跑个流程】
  • 【新品发布】嵌入式人工智能实验箱EDU-AIoT ELF 2正式发布
  • 学习python day9
  • 为什么共现矩阵是高维稀疏的
  • 攻防世界-safer-than-rot13
  • 各个链接集合
  • Jenkins实践(7):Publish over SSH功能
  • 自然语言处理入门及文本预处理
  • STM32的HAL编码流程总结(上部)
  • LY/T 2714-2016 木塑门套线检测
  • 流媒体网站建设/查询友情链接
  • 用自己的手机做网站/公司网站费用
  • 个人网站要备案嘛/杭州网站seo
  • 新闻发稿114/站长工具之家seo查询
  • 邵东平台网站建设/网上找客户有什么渠道
  • wordpress 只剩纯文本/seo优化方案策划书