当前位置: 首页 > 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;
}

http://www.xdnf.cn/news/674425.html

相关文章:

  • WPF【10_2】数据库与WPF实战-示例
  • 中级统计师-统计学基础知识-第七章 回归分析
  • 8.安卓逆向2-frida hook技术-frida环境安装
  • 【IOS】【OC】【应用内打印功能的实现】如何在APP内实现打印功能,连接本地打印机,把想要打印的界面打印成图片
  • 简单网络交换、路由-华三单区域OSPF
  • AGI大模型(34):Advanced RAG之Pre-Retrieval(预检索)优化
  • OpenAI O3惊现算法的自由意识,AGI初现?
  • 在VSTO C#中获取Excel范围内最后一个非空单元格,可以通过以下几种方法实现
  • C标准库函数:字符串操作
  • 【深度学习】7. 深度卷积神经网络架构:从 ILSVRC、LeNet 到 AlexNet、ZFNet、VGGNet,含pytorch代码结构
  • NLP助力非结构化文本抽取:实体关系提取实战
  • 【ASR】基于分块非自回归模型的流式端到端语音识别
  • qt之开发大恒usb3.0相机二
  • Pytorch
  • 题目 3341: 蓝桥杯2025年第十六届省赛真题-抽奖
  • 颠覆传统,智领未来——UMI企业智脑:重新定义企业智能化转型的全新可能
  • 不同电脑同一个网络ip地址一样吗?如何更改
  • ODSA架构与操作-1
  • 【Elasticsearch】_update api的增量更新
  • 企业级RAG技术实战指南:从理论到落地的全景解析
  • .NET用C#设置Excel单元格和工作表的背景
  • AI大模型学习三十、ubuntu安装comfyui
  • vue3简介以及创建第一个vue3工程
  • 无人机仿真环境(3维)附项目git链接
  • 仓颉入门:特性
  • Elasticsearch的运维
  • ubuntu20.04安装CUDA、Cudnn
  • 深度学习————注意力机制模块
  • Milvus向量数据库DML操作实战教程
  • android平台驱动开发(四)--系统属性节点控制GPIO