先看一个简单的问题:给出N个正整数,再给出M个正整数,问这M个数中的每一个数是否在N个数中出现过,其中,N,M<=105,且所有正整数都不超过105.时间复杂度为O(M+N).
#include<cstdio>
const int maxn = 100010;
bool hashTable[maxn] = false;
int main(){
int n,m,x;
scanf("%d%d",&n,&m);
for(int i = 0;i<n;i++){
scanf("%d",&x);
hashTable[x] = true;
}
for(int i = 0;i<m;i++){
scanf("%d",&x);
if(hashTable[x] == true){
printf("YES\n");
}else{
printf("NO\n");
}
}
return 0;
}
如果题目要求M个欲查询的数中每个数在N个数中出现的次数,那么可以把hashTable数组替换为int型,然后在输入N个数时进行预处理,即当输入的数为x时,就令hashTable[x]++,这样就可以达到O(M+N)复杂度。
#include<cstdio>
const int max = 100010;
bool hashTable[max] = {0};
int main(){
int n,m,x;
scanf("%d%d",&n,&m);
for(int i = 0;i<n;i++){
scanf("%d",&x);
hashTable[x]++;
}
for(int i = 0;i<m;i++){
scanf("%d",&x);
printf("%d\n",hashTable[x]);
}
return 0;
}
上面的两个问题都有一个特点,那就是直接把输入的数作为数组的下标来对这个数的性质进行统计。如果key不是整数,那么又应当如何设计散列函数呢?
将字符串映射为一个整数
int hashFunc(char S[],int len){
int id = 0;
for(int i = 0;i<len;i++){
id = id*26 +(S[i]-'A');
}
return id;
}
以一个问题结尾,给出N个字符串(由恰好三位大写字母组成),再给出M个查询字符串,问每个查询字符串在N个字符串中出现的次数。
#include<cstdio>
const int maxn = 100;
char S[maxn][5],temp[5];
int hashTable[26*26*26+10];
int hashFunc(char S[],int len){
int id = 0;
for(int i = 0;i<len;i++){
id = id*26 + (S[i] - 'A');
}
return id;
}
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i = 0;i<n;i++){
scanf("%s",S[i]);
int id = hashFunc(S[i],3);
hashTable[id]++;
}
for(int i = 0;i<m;i++){
scanf("%s",temp);
int id = hashFunc(temp,3);
printf("%d\n",hashTable[id]);
}
return 0;
}