标签:problem 冲突 重点 现在 oid value 退出 先来 提醒
Hash,一般翻译做散列、杂凑,或音译为哈希。————摘自百度百科
先来看个题:给你一坨一些键值集<key,value>
,\(key\)的范围是\([1,10^{10}]\),每次询问\(x\),回答\(key=x\)的\(value\)这种一看就知道暴力不行……于是,有些同学会说:我会用map
!但map
的查询是 \(O(logn)\)的 QwQ。那么哈希可以怎么做呢?我们可以让\(hash[f(key)]=value\),其中\(f()\)函数被称为哈希函数。至于\(f()\)函数怎么写……想怎么写就怎么写!没错,你想怎么写就怎么写。一般有这么几种方法:
那么现在上面那个问题就好解决了,只要用取余数法求得\(key\)的哈希地址就可以大大压缩空间了!
但是,你不要高兴太早!相信有许多人已经看出来了,哈希的缺点很明显,就是容易出现不同的元素有同一个哈希地址的情况,我们一般称其为:哈希冲突。那么有什么方法能解决哈希冲突呢?有许多方法:
0 0 0 34 6 44 0 0
注:0表示没有元素。然后又有一个元素\(8\),得到其哈希地址也是4(即34所在的位置),那么我们就往后挪一挪:大哥你先来的,我到后面去。于是来到了6的位置——也被占了,那么再往后移……最后到了7(即44后面那个)。然后查询时只要依次往后找就可以了。解决哈希冲突的方法一般就是这些啦!还有个问题,上面提到模数要是质数,为什么呢?原因很简单,根据质数的特性,质数每一个位置都能很好的利用起来,而合数不可以。而且这个质数要大一点(废话,你来个19,玩个鬼哦)。
好,讲完了基础的,来看一看例题:
P3370 【模板】字符串哈希
噫,刚刚只说了整数哈希啊!没关系,记得ASCII码吗?我们可以通过ASCII码,将其转成一个\(base\)进制数,当然,是模过的。然后再用链地址法,对同一哈希值的字符串进行遍历,如果都不相同,加入并更新答案。
具体代码实现:
#include<cstdio>
#include<string>
#include<vector>
#include<iostream>
#define mod 23333
#define base 298
#define rg register
using namespace std;
int n,ans;
string s;
vector<string>v[mod+5];
void insert()
{
int hash=1;//记录哈希值,由于后面要乘所以初值是1
for(rg int i=0;i<s.length();i++)
hash=(1ll*hash*base+s[i])%mod;//1ll就是(long long)1,乘一个1ll,可以保证不爆精度(当然你爆long long或高精度我也没办法)
string t=s;//暂存一下
for(rg int i=0;i<v[hash].size();i++)
if(v[hash][i]==t) return ;//判断,如果有相同的就退出
v[hash].push_back(t);//加入新的字符串
ans++;//更新答案
return ;
}
int main()
{
scanf("%d",&n);
for(rg int i=1;i<=n;i++)
{
cin>>s;
insert();
}
printf("%d",ans);
return 0;
}
哦对了,一般233333(2后面跟一堆3)、100007(1和7中间隔一堆0)、1000009(1和9中间隔一堆0)都是质数。
就讲这么多吧,之后就要靠大家自己实现了!重点还是在多刷题啊!
标签:problem 冲突 重点 现在 oid value 退出 先来 提醒
原文地址:https://www.cnblogs.com/mk-oi/p/13549767.html