哈希表之字符串哈希

哈希算法对字符串的处理,有一个很强大的功能就是询问字符串的两个子串是否相同,特别适合于那种询问次数很多的情况下,可以避免超时。

来一个具体的题目

 

 接下来我们来分析一下字符串哈希的概念

字符串哈希其实就是把字符转换成数字(也就是哈希值字符串有很多种字符,为此我们为区别不同字符我们赋予每个字符不同的值,这里我们直接借用字符的ASCII码来代表每个字符的值,同时我们最后的哈希值设为P进制,(经验值来看P一般取131,或者13331)接下来我们就可以求出前i个字符组成的子串的哈希值

    char str[N];//用来存储字符串
    P=131//代表这里哈希值是一个131进制的数
    unsigned long long h[100010];//h数组设在main()函数外则默认初始为0
    cin>>str+1;//从str+1开始读入
    for(int i=1;i<=n;i++)//从i=1开始
        h[i] = h[i - 1] * P +str[i];//h[i]代表字符串的前i个字符组成的字串的哈希值

但是我们知道字符串可能是很长,那么求出来的哈希值就会很大,所以这里我们用到了哈希的特点映射,把求出来的哈希值对2的64次方取模,这里有一个简便的方法就是用unsign long long数据类型来存储哈希值,因为该数据结构的取值范围为0~2的64次方,因此当溢出的时候就相当于对2的64次方取余的过程。

(映射取余,都会出现一个问题,那就是余数相同的冲突,为此字符串哈希不像之前的模拟散列表去解决这个冲突,而是去一些经验值来使得几乎没有可能性产生冲突,也就是P=131或13331,和对2的64次方就是这个经验值)对此有疑问的小伙伴可以去查找资料进一步了解。

有了前i个字符的字串的哈希值我们可以轻松得到任意连续字串的哈希值

ULL get(int l,int r){//这是一个求连续字串哈希值的函数
    return h[r]-h[l-1]*p[r-l+1];//这里就要是求l~r区间的哈希值
}

最后我们给出完整的字符串哈希代码

#include <iostream> 

using namespace std;

const int N = 100010, P = 131;//经验值P=131或者13331

typedef unsigned long long ULL;//unsigned long long的取值范围是0~2的64次方,同时是无符号,因此用ULL存储值就相当于对2的64方取余,利用了取值范围的溢出

char str[N];
ULL h[N],p[N];//p[N]数组用来打表避免重复计算P的多次方

ULL get(int l,int r){//这是一个求出任意字符串哈希值的函数
    return h[r]-h[l-1]*p[r-l+1];//这里就要是求l~r区间的哈希值
}
int main(){
    int n,m;
    cin>>n>>m;
    cin>>str+1;//从str+1开始读入
    p[0]=1;
    for(int i=1;i<=n;i++){//从i=1开始
        p[i]=p[i-1] * P;
        h[i] = h[i - 1] * P +str[i];//h[i]代表前i个字符组成的字符串的哈希值
    }
    while(m--){
        int l1,r1,l2,r2;
        cin>>l1>>r1>>l2>>r2;//读入两个字符串的左右界限
        if(get(l1,r1)==get(l2,r2))puts("Yes");//对比两个字符串的哈希值是否相同
        else puts("No");
    }
    return 0;
}

到头了,字符串哈希就讲完了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值