很久没遇到过hash的题了,今天来重新温故一下
@[toc]
序言
你有没有想过,字符串存储一大溜,比较时又麻烦又折腾,我当年oi时就想要是能转化成整数就好了,
诶,字符串hash其实就是把一个字符串转化成整数
你也可以把hash的过程理解成加密,但是不同字符串加密后的“密文”互不相同
说起来容易,我们怎么才能做到不冲突不重复呢?这里就开始讲解hash
常用的几个字符串hash方法:
S=s1s2s3s4......sn
idx(s[i]) = s[i] - 'a'
hash公式(自然溢出)
讲解
unsigned long long hash[N];
hash[i]=hash[i-1]*p + s[ i ] (自动取模)
p为质数(常取31)
unsigned long long的范围会自然一处,相当于自动对2^64^ 取獏
模板
char s[10010]; ull hashs(char s[]) { int len=strlen(s); ull base=131; ull ans=0; for (int i=1;i<=len;i++) ans=ans*base+(ull)s[i]; return ans&0x7fffffff;//舍弃符号位 }
首位是符号位,& 0x7fffffff之后符号位固定为0(代表正数),后面保持不变(可以理解成取正)
单hash
讲解
hash [ i ] = ( hash [ i - 1 ] * p + idx ( s [ i ] ) ) % mod
其中p与mod均为质数
对了,p与mod越大,重复的概率越低
模板
char s[10010]; ull mod=101; ull hashs(char s[]) { int len=strlen(s); ull base=13; ull ans=0; for (int i=1;i<=len;i++) ans=(ans*base+(ull)s[i])%mod; return ans; }
双hash
讲解
如果单hash你不放心,可以用双hash,更保险
将一个字符串hash两次,生成一个二元组,来代表原字符串,两个都比配才可以(相当于两把锁)
hash1[i]=(hash1[i−1]) ∗ p + idx(s[i]) % mod1
hash2[i]=(hash2[i−1])∗p + idx (s[i]) % mod2
pair< hash1 , hash2 > 表示一个字符串!
代码
char s[100]; ull mod1=13; ull mod2=17; ull hash1(char s[]) { int len=strlen(s); ull ans=0; for (int i=0;i<len;i++) ans=(ans*base+(ull)s[i])%mod1; return ans; } ull hash2(char s[]) { int len=strlen(s); ull ans=0; for (int i=0;i<len;i++) ans=(ans*base+(ull)s[i])%mod2; return ans; }
总结
对于一个字符串,我们可以预处理1~L的hash值,这样通过O(1)的方法递推出来