字串雜湊[hash模板]
阿新 • • 發佈:2018-12-14
有這麼一類神奇的問題,給你一堆字串,然後問你有多少本質不同的字串
~~ 或許有頭鐵的同志可以開一個map ~~ 所以有了hash大法
大致思想
我們判斷兩個字串相等,無非就是判斷他們每一位是不是相等,但是如果讓你判斷兩個數字是不是相等,是不是就簡單了許多呢?答案是顯然的,hash的大致思想也在這裡,把字串表示成一個數字,然後判斷是不是想等,然後於是同學們有疑問了,"怎麼轉成數字,聽著容易,而且不會和數字串判錯嗎?"為了解決這些問題,我們有了機智的應對方法,轉成其他進位制下的數字,具體長啥樣不需要關心,我們就判個等就好
操作過程
對於一個串s,假如我們把它轉成base進位制下的數字,怎麼轉呢?我們先把每個字元強轉成他對應的ascll碼值,然後他現在是一個十進位制的數字,然後執行如下操作 $ hash=(hash \ast base+(ull)s[i])%mod$,體會一下這個過程,每次把每一位乘上一個base,相當於集體左移,給新加入的元素留出位置,然後我們就得到了這個串的hash值,然後加入一個數組裡,排個序,判等就好了
一些嘮叨話
主流的hash有好幾種,我寫的有unsigned long long自然溢位,就不需要取模了,還有單模數hash,雙模數hash,第二種比第一種難卡 ,看個人喜好吧,然後就是對於取模用的質數,不要用一些主流的素數,比如什麼19260817,998244353,2147483647,還有某不明深意的hhh質數,總之如果你臉黑,碰巧遇到出題人心情好,你的程式可能就會被對著卡資料了。。。
程式碼
自然溢位
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int M=100500;
const ull emm=0x7fffffff;
ull base=117;
ull a[M];int n;
char s[M];
inline ull mhash(char g[])
{
int len=strlen(g);
ull hs=0;
for (int i=0;i<len;i++)
hs=hs*base+(ull)(g[i]);
return hs&emm;
}
signed main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
a[i]=mhash(s);
}
sort(a+1,a+n+1);int ans=1;
for (int i=2;i<=n;i++)
if (a[i]!=a[i-1]) ans++;
cout<<ans;
return 0;
}
單模數
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int M=100500;
const ull mod=200209171;
ull base=174;
ull a[M];int n;
char s[M];
inline ull mhash(char g[])
{
int len=strlen(g);
ull hs=0;
for (int i=0;i<len;i++)
hs=(hs*base+(ull)(g[i]))%mod;
return hs;
}
signed main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
a[i]=mhash(s);
}
sort(a+1,a+n+1);int ans=1;
for (int i=2;i<=n;i++)
if (a[i]!=a[i-1]) ans++;
cout<<ans;
return 0;
}
雙模數
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ull unsigned long long
using namespace std;
const int M=100500;
const ull m1=200209171;
const ull m2=200207261;
ull base=174;
struct hsh
{
ull h1,h2;
}a[M];
char s[M];int n;
inline ull hash1(char g[])
{
int len=strlen(g);
ull hs=0;
for (int i=0;i<len;i++)
hs=(hs*base+(ull)g[i])%m1;
return hs;
}
inline ull hash2(char g[])
{
int len=strlen(g);
ull hs=0;
for (int i=0;i<len;i++)
hs=(hs*base+(ull)g[i])%m2;
return hs;
}
inline bool cmp(hsh a,hsh b)
{return a.h1<b.h1;}
signed main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%s",s);
a[i].h1=hash1(s);
a[i].h2=hash2(s);
}
sort(a+1,a+n+1,cmp);int ans=1;
for (int i=2;i<=n;i++)
if (a[i].h1!=a[i-1].h1||a[i].h2!=a[i].h2) ans++;
cout<<ans;
return 0;
}