1. 程式人生 > >字串雜湊[hash模板]

字串雜湊[hash模板]

有這麼一類神奇的問題,給你一堆字串,然後問你有多少本質不同的字串

~~ 或許有頭鐵的同志可以開一個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;
}