字符串哈希[hash模板]

版权声明:我这么弱的蒟蒻,虽然博文不是很好,但也请标明转发地址喵! https://blog.csdn.net/ACerAndAKer/article/details/82963537

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

或许有头铁的同志可以开一个map
所以有了hash大法

大致思想

我们判断两个字符串相等,无非就是判断他们每一位是不是相等,但是如果让你判断两个数字是不是相等,是不是就简单了许多呢?答案是显然的,hash的大致思想也在这里,把字符串表示成一个数字,然后判断是不是想等,然后于是同学们有疑问了,"怎么转成数字,听着容易,而且不会和数字串判错吗?"为了解决这些问题,我们有了机智的应对方法,转成其他进制下的数字,具体长啥样不需要关心,我们就判个等就好

操作过程

对于一个串s,假如我们把它转成base进制下的数字,怎么转呢?我们先把每个字符强转成他对应的ascll码值,然后他现在是一个十进制的数字,然后执行如下操作
hash=(hash * 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;
}

猜你喜欢

转载自blog.csdn.net/ACerAndAKer/article/details/82963537