散列的定义与整数散列
先来看一个简单的问题:给出N个正整数,再给出M个正整数,问这M个数中的每个数分别是否在N个数中出现过,其中N,M≤10 5,且所有正整数均不超过10 5。例如N=5,M=3,N个正整数为{8,3,7,6,2},欲查询的M个正整数为{7,4,2},于是后者中只有7和2在N个正整数中出现过,而4是没有出现过的。对这个问题,最直观的思路是:对每个欲查询的正整数x,遍历所有N个数,看是否有个数与x相等。这种做法的时间复杂度为O(NM),当N和M都很大(10 5级别)时,显然是无法承受的。那么该如何做呢?ー一不妨用空间换时间,即设定一个bool型数组 hashTable[100010]其中 hashTable[x]=true表示正整数x在N个正整数中出现过,而 hash Table[x]= false表示正整数x在N个正整数中没有出现过。这样就可以在一开始读入N个正整数时就进行预处理,即当读入的数为x时,就令 hashtable x]=tnue(说明:hash Table数组需要初始化为 false,表示初始状态下所有数都未出现过)。于是,对M个欲查询的数,就能直接通过 hash Table数组
判断出每个数是否出现过。显然这种做法的时间复杂度为O(N+M),代码如下:
include <cstdio>
const int maxn a 100010;
bool hashtable[maxi ]={false}:
int main( ){
int n, m, x;
scanf("dd",&n,&m);
for(int1=0:1<n:1++)
scanf("%d", &x):
hashTable [x]=true;//数字x出现过
}
for(int1=0;1<m;1++)
scanf("%d",&x)
if( hashtable[x]==true)(//如果数字x出现过,则输出YES
printf ("YES \n");
}else{
printf("No\n");
}
}
return 0:
}
同样的,如果题目要求M个欲查询的数中每个数在N个数中出现的次数,那么可以把
hashtable数组替换为int型,然后在输入N个数时进行预处理,即当输入的数为x时,就令
hash Table[x]++,这样就可以用ON+M)的时间复杂度输出每个欲查询的数出现的次数。代码
如下:
Include <cstdio>
const int maxn =100010;
int hashtable[maxn]={0};
int main(){
int n, m, x;
scanf("%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:
}
上面的两个问题都有一个特点,那就是直接把输入的数作为数组的下标来对这个数的性
质进行统计(这种做法非常实用,请务必掌握)。这是一个很好的用空间换时间的策略,因为
它将查询的复杂度降到了O(1)级别。但是,这个策略暂时还有一个问题一一上面的题目中出
现的每个数都不会超过10,因此直接作为数组下标是可行的,但是如果输入可能是10°大小
的整数(例如1111或者甚至是一个字符串(例如" Love You"),就不能将它们直接
作为数组下标了。要是有一种做法,可以把这些乱七八槽的元素转换为一个在能接受范围内
的整数,那该多么美好呀!