当前位置: 首页 > news >正文

字符串哈希

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<len;i++)
    	ans=(ans*base+(ull)s[i])%mod+prime;
    return ans;
}

自然溢出哈希

根据 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<len;i++)
    	ans=ans*base+(ull)s[i];
    return ans;
}

双哈希

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

ull base=131;
ull mod1=19260817,mod2=19660813;

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;
}

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<m) return -1;
    ull bn=1;
    for(int i=0;i<m-1;i++) bn=bn*base;
    ull key=0,cur=0;
    for(int i=0;i<m;i++){
        key=key*base+(t[i]-'a');
        cur=cur*base+(s[i]-'a');
    }
    for(int i=0;i<n-m+1;i++){
        if(cur==key) return i;
        cur=cur-bn*(s[i]-'a');
        cur=cur*base+(s[i+m]-'a');
    }
    return -1;
}

动态维护子串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^i

void 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<l || y<r) return 0;
    if(x<=l && y<=r) return sgt[i];
    int mid=(l+r)>>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];
}

相关文章:

  • 从员工、猎头到创业者的职场经验——《程序员羊皮卷》书评(3)
  • 整除分块
  • 《程序员羊皮卷》飙升当当IT新书热卖榜第二名
  • 洛谷 P2261 [CQOI2007]余数求和(整除分块)
  • 如何定义一本好书——《程序员羊皮卷》书评(2)
  • Win32 OpenGL编程(10) 视口变换
  • SQL SERVER 的 CLR 存储过程
  • 有用的Oracle 管理工具 for windows助手
  • 现代软件构建系统的使用 CMake简介
  • 搜集的一些RTMP项目,有Server端也有Client端
  • .NET的数据绑定
  • 从员工、猎头到创业者的职场经验——《程序员羊皮卷》书
  • 完成从学习者到社会人的转变——《程序员羊皮卷》连载(14)
  • 百度全面放弃竞价排名的原因
  • Mobile Market如何能像淘宝网一样流行?
  • #Java异常处理
  • [nginx文档翻译系列] 控制nginx
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • 2019.2.20 c++ 知识梳理
  •  D - 粉碎叛乱F - 其他起义
  • ES6 ...操作符
  • flask接收请求并推入栈
  • go语言学习初探(一)
  • idea + plantuml 画流程图
  • java正则表式的使用
  • magento2项目上线注意事项
  • Mysql5.6主从复制
  • session共享问题解决方案
  • 机器学习学习笔记一
  • 基于遗传算法的优化问题求解
  • 事件委托的小应用
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • #13 yum、编译安装与sed命令的使用
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2)关于RabbitMq 的 Topic Exchange 主题交换机
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (Redis使用系列) Springboot 使用Redis+Session实现Session共享 ,简单的单点登录 五
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (九)信息融合方式简介
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (生成器)yield与(迭代器)generator
  • (一)Linux+Windows下安装ffmpeg
  • (一)Neo4j下载安装以及初次使用
  • (译) 理解 Elixir 中的宏 Macro, 第四部分:深入化
  • (原創) 如何安裝Linux版本的Quartus II? (SOC) (Quartus II) (Linux) (RedHat) (VirtualBox)
  • (原創) 如何動態建立二維陣列(多維陣列)? (.NET) (C#)
  • .NET Conf 2023 回顾 – 庆祝社区、创新和 .NET 8 的发布
  • .net websocket 获取http登录的用户_如何解密浏览器的登录密码?获取浏览器内用户信息?...
  • .NET成年了,然后呢?
  • .net反编译工具
  • .NET设计模式(8):适配器模式(Adapter Pattern)
  • [100天算法】-目标和(day 79)
  • [2024] 十大免费电脑数据恢复软件——轻松恢复电脑上已删除文件
  • [Android]How to use FFmpeg to decode Android f...