字符串哈希[hash模板]

匿名 (未验证) 提交于 2019-12-02 22:56:40

有这么一类神奇的问题,给你一堆字符串,然后问你有多少本质不同的字符串

~~ 或许有头铁的同志可以开一个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; } 
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!