mmxingye

导航

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 2022-06-20 15:11  独立树  阅读(80)  评论(0编辑  收藏  举报