进制哈希
进制哈希的作用:把字符赋予进制和模数,将每一个字符串映射为一个小于模数数字。
具体操作:首先设一个进制数base,并设一个模数mod,进制哈希就是把一个串转化为一个值,这个值是base进制的,储存在哈希表中,注意一下在存入的时候取模一下即可。
哈希冲突:什么是哈希冲突:比如 wsy 的哈希值是2333,然而 mxq 的哈希值也是2333,这样就会产生哈希冲突,从而让哈希算法判断失误。
解决办法:
- 用一个大质数当模数
- 双模数哈希:(通过设置两个不同的哈希方式,对于一个字符串,当且仅当两个哈希值都相同时才判定相同。)
- 自然溢出法
核心代码:
#define base 233317 #define inf 212370440130137957(LL) ull mod = inf; ull hasha(char s[]){ ll ans=0, len=strlen(s); for(ll i=0;i<len;i++){ ans = (ans*base + (ull)s[i])%mod; //枚举该字符串的每一位,与base相乘,转化为base进制,加(ull)是为了防止爆栈搞出一个负数,(ull)是无符号的,但其实加了一个ull是可以不用mod的,加个mod更保险 //然而加了mod会很玄学,莫名比不加mod慢 } return ans; }
模板题目:P3370 【模板】字符串哈希
1.自然溢出法 AC_Code:
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 const int maxn = 10000+10; 11 const ull base = 233317; 12 const ull mod = 1e9+7; 13 14 int n; 15 char s[maxn]; 16 ull hash_key[maxn]; 17 18 ull get_hash(char s[]){ 19 ull ans=0; 20 int len=strlen(s); 21 for(int i=0;i<len;i++){ 22 ans = (ans*base + (ull)s[i]); 23 //这里不使用mod让它自然溢出,定义为ull的数在超过2^32的时候会自然溢出(自然溢出看队友的解释,相当于自动对pow(2,64)-1 取模,无需再手动取模) 24 //如果把这个换成上面的hash就会400ms+ 25 //所以说自然溢出大法好 26 } 27 return ans; 28 } 29 30 int main() 31 { 32 scanf("%d",&n); 33 for(int i=1;i<=n;i++){ 34 scanf("%s",s); 35 hash_key[i] = get_hash(s); 36 } 37 sort(hash_key+1,hash_key+1+n); 38 int ans=1; 39 for(int i=1;i<n;i++){ 40 if( hash_key[i]!=hash_key[i+1] ){ 41 ans ++; 42 } 43 } 44 printf("%d\n",ans); 45 return 0; 46 }
2.双哈希AC_Code:(其实就是用两个不同的mod来算hash,哈希冲突的概率是降低了很多,不过常数大,容易被卡,这道题要400ms+)
1 #include <iostream> 2 #include <cstdio> 3 #include <vector> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 using namespace std; 8 typedef long long ll; 9 typedef unsigned long long ull; 10 11 const int maxn = 10000+10; 12 const ull base = 233317; 13 const ull mod1 = 1e9+7; 14 const ull mod2 = 212370440130137957; 15 16 int n; 17 char s[maxn]; 18 struct node{ 19 ll x,y; 20 }hash_key[maxn]; 21 22 bool cmp1(node a, node b){ 23 return a.x < b.x; 24 } 25 bool cmp2(node a, node b){ 26 return a.y < b.y; 27 } 28 29 ull hash1(char s[]){ 30 ull ans=0; 31 int len=strlen(s); 32 for(int i=0;i<len;i++){ 33 ans = (ans*base + (ull)s[i])%mod1; 34 } 35 return ans; 36 } 37 38 ull hash2(char s[]){ 39 ull ans=0; 40 int len=strlen(s); 41 for(int i=0;i<len;i++){ 42 ans = (ans*base + (ull)s[i])%mod2; 43 } 44 return ans; 45 } 46 47 int main() 48 { 49 scanf("%d",&n); 50 for(int i=1;i<=n;i++){ 51 scanf("%s",s); 52 hash_key[i].x = hash1(s); 53 hash_key[i].y = hash2(s); 54 } 55 sort(hash_key+1,hash_key+1+n,cmp1); 56 sort(hash_key+1,hash_key+1+n,cmp2); 57 int ans = 1; 58 for(ll i=1;i<n;i++){ 59 if( hash_key[i].x!=hash_key[i+1].x || hash_key[i].y!=hash_key[i+1].y){ 60 ans ++; 61 } 62 } 63 printf("%d\n",ans); 64 return 0; 65 }
参考博客:here