字典树(Trie)
1.AC 自动机
2.字典树(Trie)
-
字典树
例题
原理
本质上是存储若干个字符串的公共前缀以减少重复的查询操作,达到提高查询效率的目的。
(本题中的字符串只含数字与大小写字母,所以一共有62个字符)
ch[N][65]
:ch[p][j]
存储从节点 'a'
到 'z'
,'A'
到 'Z'
,'0'
到 '9'
一共
cnt[N]
:cnt[p]
用来存储节点
idx
:idx
用于给节点编号。
插入操作
初始阶段仅有一个空节点,编号为
查询操作
从根开始查,扫描字符串。如果有字符 s[i]
,则继续往下走,能走到词尾,则返回访问次数;无字符 s[i]
,则返回
代码
#include <iostream> #include <cstring> using namespace std; const int N = 3000005; char str[N]; int ch[N][65], cnt[N], idx; int getnum(char c) {//映射字符 if (c >= 'a' && c <= 'z')return c - 'a'; else if (c >= 'A' && c <= 'Z')return c - 'A' + 26; else if (c >= '0' && c <= '9')return c - '0' + 52; else return -1; } void insert(char s[]) {//插入操作 int p = 0; for (int i = 0; s[i]; i++) { int j = getnum(s[i]); if (!ch[p][j])ch[p][j] = ++idx; p = ch[p][j]; cnt[p]++;//将cnt[p]++放在循环内部是因为题目要求查询前缀中含有待查询序列的字符串 } //如果目的是查询与被查询字符串相等的字符串的个数,就将插入操作改为 /* int p = 0; for (int i = 0; s[i]; i++) { int j = getnum(s[i]); if (!ch[p][j])ch[p][j] = ++idx; p = ch[p][j]; } cnt[p]++; */ } int query(char s[]) {//查询操作 int p = 0; for (int i = 0; s[i]; i++) { int j = getnum(s[i]); if (!ch[p][j])return 0; p = ch[p][j]; } return cnt[p]; } void solve() { int n, q; cin >> n >> q; //清空之前使用过的数组 for (int i = 0; i <= idx; i++) { for (int j = 0; j < 65; j++)ch[i][j] = 0; cnt[i] = 0; } idx = 0; for (int i = 1; i <= n; i++) { cin >> str; insert(str); } for (int i = 1; i <= q; i++) { cin >> str; cout << query(str) << endl; } } int main() { ios::sync_with_stdio(0); int T; cin >> T; while (T--) { solve(); } return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】