字符串哈希
发布日期:2021-05-07 02:28:41 浏览次数:27 分类:精选文章

本文共 2476 字,大约阅读时间需要 8 分钟。

hash函数

设字符集大小为 B B B,将所有字符编号为 0 , 1 , . . . , B − 1 0,1,...,B-1 0,1,...,B1,则一个串可以看做一个 B B B进制数,以 B B B进制展开计算一个长 m m m的串 t t t h a s h hash hash值, P P P是一个大质数,减少碰撞次数

H a s h ( t ) = ∑ i = 0 m − 1 t i ⋅ B m − i + 1   m o d   P Hash(t)=\sum_{i=0}^{m-1}{ t_i·B^{m-i+1}~mod~P} Hash(t)=i=0m1tiBmi+1 mod P

单模数哈希

ull base=131;int prime=233317;ull mod=212370440130137957LL;ull hash(char *s){       int len=strlen(s);    ull ans=0;    for(int i=0;i

自然溢出哈希

根据 u s i g n e d    l o n g    l o n g usigned~ ~long~~ long usigned  long  long自然溢出的性质优化(溢出自动取模)

ull base=131;ull hash(char *s){       int len=strlen(s);    ull ans=0;    for(int i=0;i

双哈希

更安全的做法是双哈希,翻车几率更低

ull base=131;ull mod1=19260817,mod2=19660813;ull hash1(char *s){       int len=strlen(s);    ull ans=0;    for(int i=0;i

hash函数的滚动性质

H ( s , l , r ) H(s,l,r) H(s,l,r)为串 s s s的子串 s l s l + 1 . . . s r s_ls_{l+1}...s_r slsl+1...sr h a s h hash hash值,则:

H ( s , l + 1 , r + 1 ) = ( H ( s , l , r ) − s l B r − l ) ⋅ B + S r + 1 H(s,l+1,r+1)=(H(s,l,r)-s_lB^{r-l})·B+S_{r+1} H(s,l+1,r+1)=(H(s,l,r)slBrl)B+Sr+1

在这里插入图片描述
例如找串 s s s中是否包含子串 t t t

利用滚动性质,先 O ( m ) O(m) O(m)求出模式串 t t t h a s h hash hash值,然后 O ( n ) O(n) O(n)扫一遍文本串 s s s所有长 m m m的子串的 h a s h hash hash值,就可以找出匹配

ull base=131;int rabin_karp(char *t,char *s){       int n=strlen(s),m=strlen(t);    if(n

动态维护子串hash

区间的 h a s h hash hash是可合并的,即如果知道了 H ( s , l , m i d ) H(s,l,mid) H(s,l,mid) H ( s , m i d + 1 , r ) H(s,mid+1,r) H(s,mid+1,r),则:

H ( s , l , r ) = ( H ( s , l , m i d ) ∗ B r − m i d + H ( s , m i d + 1 , r ) )   m o d   P H(s,l,r)=(H(s,l,mid)*B^{r-mid}+H(s,mid+1,r))~mod~P H(s,l,r)=(H(s,l,mid)Brmid+H(s,mid+1,r)) mod P

问题引入

维护子串的 h a s h hash hash值,有两种操作:

  • 单点修改:可以将 s s s的某个字符修改为 c c c
  • 区间查询:查询 s s s的子串 s l s l + 1 . . . s r s_ls_{l+1}...s_r slsl+1...sr h a s h hash hash
ull base=131;char s[maxn];ull sgt[maxn*4],bn[maxn]; //bn[i]=base^ivoid build(int i,int l,int r){       if(l==r){           sgt[i]=s[l]-'a';        return;    }    int mid=(l+r)>>1,k=i<<1;    build(k,l,mid);    build(k|1,mid+1,r);    sgt[i]=sgt[k]*bn[r-mid]+sgt[k|1];}ull query(int i,int l,int r,int x,int y){       if(x
>1,k=i<<1; int len=max(0,max(r,y)-max(mid+1,x)+1); return query(k,l,mid,x,y)*bn[len]+query(k|1,mid+1,r,x,y);}void modify(int i,int l,int r,int pos,char x){ if(l==r){ sgt[i]=x-'a'; return; } int mid=(l+r)>>1,k=i<<1; if(pos<=mid) modify(k,l,mid,pos,x); else modify(k|1,mid+1,r,pos,x); sgt[i]=sgt[k]*bn[r-mid]+sgt[k|1];}
上一篇:整除分块
下一篇:2020牛客暑期多校第二场 F - Fake Maxpooling(dp/单调队列)

发表评论

最新留言

很好
[***.229.124.182]2025年03月31日 13时48分32秒