写这篇博客仅是为了凑齐神龙,真想学Hash请另寻高明.
关于哈希Hash,我没有找到什么专门学习它的博客.因为它实在是不太好讲,但实现起来其实是很容易的,它的思想很简单,可是就是不太好阐释,而且它就像离散化一样,一般情况下都用于对数据的预处理.
反正我对Hash的理解就是,当碰到一些很难处理的数据时(比如字符串、很大的数等等),可以考虑将它通过哈希函数变成一个较小的常数,这个较小的常数就称作哈希值.
真的不想再用文字来叙述这个东西了
字符串哈希:(最常用,最重要)
给出两个仅含大写字母的字符串s1,s2,求s1在s2中出现了多少次.
unsigned long long power[MAXN],sum[MAXN];
//unsigned long long
char s1[MAXN],s2[MAXN];
int main(){
power[0]=1;
for(int i=1;i<=MAXN;i++)
power[i]=power[i-1]*b;
//预处理出b^n,b是一个质数(自行赋值).
scanf("%s%s",s1+1,s2+1);
int n=strlen(s1+1),m=strlen(s2+1);
for(int i=1;i<=m;i++)
sum[i]=sum[i-1]*b+s2[i]-'A'+1;
//计算主串s2的哈希值
//这是字符串哈希的精髓,好好理解一下
unsigned long long s=0;
for(int i=1;i<=n;i++)
s=s*b+s1[i]-'A'+1;
//计算匹配串s1的哈希值
//因为我们要计算的是s1在s2中出现的次数,所以是要拿s1
//整个串的哈希值和s2的部分串的哈希值比较,看是否相等
//这就是为什么本题中s1的哈希值直接用变量s存,而s2的
//哈希值要存在一个数组中
//此外,s1和s2的哈希函数(即哈希值的计算方法)要相同.
int ans=0;
for(int i=0;i<=m-n;i++)
if(s==sum[i+n]-sum[i]*power[n])
ans++;
//枚举s2的长度等于s1的子串的哈希值,如果相等,ans+1
printf("%d
",ans);
return 0;
}
哈希表:(真心觉得用得不多)
(该图是在模16意义下的哈希表):
题意:给你n个字符串,判断其中不相同的字符串的个数.
分析:做法很多,我下面的代码是将字符串哈希和哈希表的思想结合起来做的.应该会更有助于全面理解哈希.
#include<bits/stdc++.h>
using namespace std;
const int p1=47,p2=79,mod1=1e6+3,mod2=1e6+9;
//构造两个哈希函数,只有同时满足两个哈希值相等
//才是相同的字符串,能有效降低哈希冲突的概率.
int n,tot,ans;
int nxt[10005],end[10005],head[mod1+5];
string s[10005];
void insert(int x,int y){
nxt[++tot]=head[x];
head[x]=tot;
end[tot]=y;
}
//将一个字符串通过两个哈希函数得到的两个哈希值
//插入邻接表(哈希表)
//结合上面那个图来看就是把x当做表头
//y当做表头后链表上的值
int query(int x,int y){
for(int i=head[x];i;i=nxt[i]){
if(end[i]==y) return 1;
}
return 0;
}
//到哈希表中查询字符串是否存在过
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
cin>>s[i];
int len=s[i].size();
int sum1=0,sum2=0;
for(int j=0;j<len;j++){
sum1=(sum1*p1+s[i][j])%mod1;
sum2=(sum2*p2+s[i][j])%mod2;
}
//双哈希函数,这里没有让s[i][j]-'a'什么的,
//是因为字符串可能小写,可能大写,可能是数字,
//就干脆让它自己强制转换成数字就好了.
if(query(sum1,sum2)==1) ans++;
else insert(sum1,sum2);
}
printf("%d",n-ans);
return 0;
}