17 | 说过这句话吗?说过几次?(哈希表->字典树)
题目描述
三年级二班已经完成了竞选班长的投票,已知一共有n张投票,每张投票上写了一位同学的名字。
投票统计结束后,张老师随意问一个同学的名字,请编程快速检索出,该同学共有几票。
输入
第一行读入一个整数n,代表产生了n张投票;(n≤105)
接下来n行,每行有一个字符串s,代表该张投票上写的同学的姓名(姓名由不含空格的小写英文字母组成,n个姓名的总长度≤106);
接下来一行读入一个整数m(m≤105),代表王老师提问的同学的姓名数量;
接下来m行,每行有一个字符串t,代表每次询问的姓名;(姓名由不含空格的小写英文字母组成,m个姓名的总长度≤106);
输出
输出m行,第i行输出第i次询问的姓名,在投票中出现的总次数;
样例
输入
5 lihua zhaoxiang wangfang lihua zhangxiang 3 lihua wangfang sunming
输出
2 1 0
Trie字典树的解法
分析
节点数:最坏的情况下节点数(所有的单词相互都没有公共前缀) = 所有的字符数
时间复杂度:所有字符串长度和 n ,则构建字典树的时间复杂度为 O(n);要查找的字符串长度为 k ,查找的时间复杂度为 O(k)
空间复杂度: 所有字符个数和 * 字符种类
逻辑结构
每一个节点都有唯一的编号,根节点为 0 ,其余按照 1,2…… 递增
物理结构
为了维护这样的一个逻辑结构我们需要 一个邻接矩阵,一个数组(用来记录以该节点结尾的字符串个数),一个整数(用来记录节点数)
操作
插入:将字符串插入到字典树中
查询:返回字符串在字典树中出现的次数
#include <bits/stdc++.h> using namespace std; const int N = 1e6+10; int ch[N][26],idx=0; // 邻接矩阵 idx代表该数有多少个节点 int cnt[N]; // 存储以某个编号的结点结尾的单词数量 char s[N]; // 每个人的名字 int n,m; // 将字符串s插入字典树 void insert(char s[]){ int p=0; //从根节点开始查找 //循环每个字符 for(int i=0;s[i];i++){ int x=s[i]-'a'; //如果p和x之间没有边 if(!ch[p][x]) ch[p][x] = ++idx; p=ch[p][x]; // 获取当前节点的编号,我们才可以找到该节点的子节点 } cnt[p]++; // 统计以当前的 p 号节点结尾的单词数+1 } // 查询字符串 s 在字典树中出现的次数 int query(char s[]){ int p=0; for(int i=0;s[i];i++){ int x=s[i]-'a'; if(!ch[p][x]) return 0; p=ch[p][x]; } return cnt[p]; } int main(){ scanf("%d",&n); while(n--){ scanf("%s",s); insert(s); // 插入字典树 } scanf("%d",&m); while(m--){ scanf("%s",s); printf("%d\n",query(s)); } return 0; }
哈希表的解法
逻辑结构
数组+链表 = 邻接表
物理结构
三个数组,一个计数器 (注意初始化)
操作
计算哈希值
插入哈希表
查找
#include <bits/stdc++.h> using namespace std; //链表法构建哈希表 typedef unsigned long long ULL; const int N = 1e6+10; //--------物理结构--------- ULL e[N],ne[N],ad[N]; int k; // 在邻接表中的字符串个数 //----------------- char s[N]; // 每次读入的名字 int n,m; // 查找元素 x int find(ULL x){ int r=0; //次数 int h=x%N; for(int i=ad[h];i!=-1;i=ne[i]){ if(e[i]==x) r++; } return r; } // 构建哈希 void insert(ULL x){ int h=(x%N+N)%N;//防止x是负数 e[k]=x; ne[k]=ad[h]; ad[h]=k; k++; } ULL gethash(char s[]){ ULL r=0,P=131; int len = strlen(s); for(int i=0;i<len;i++){ r=r*P+s[i]; } return r; } int main(){ cin>>n; memset(ad,-1,sizeof(ad)); // 相当于 NULL while(n--){ scanf("%s",s); insert(gethash(s)); } cin>>m; while(m--){ scanf("%s",s); printf("%d\n",find(gethash(s))); } getchar(); getchar(); return 0; }
分类:
算法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)