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