mmxingye

导航

< 2025年3月 >
23 24 25 26 27 28 1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
30 31 1 2 3 4 5

统计

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)

空间复杂度: 所有字符个数和 * 字符种类

逻辑结构

image-20220617224854086

每一个节点都有唯一的编号,根节点为 0 ,其余按照 1,2…… 递增

物理结构

为了维护这样的一个逻辑结构我们需要 一个邻接矩阵,一个数组(用来记录以该节点结尾的字符串个数),一个整数(用来记录节点数)

image-20220617225050434

操作

插入:将字符串插入到字典树中

查询:返回字符串在字典树中出现的次数

#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;
}

posted on   独立树  阅读(82)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示