字符串哈希

本文介绍了字符串哈希算法的原理,通过选取固定值P(如131或13331)将字符串转化为p进制数,降低冲突率。通过前缀和计算任意子串的哈希值,实现快速比较字符串是否相等。在实际问题中,例如给定字符串和查询区间,可以高效判断两段字符串是否相同。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

字符串哈希

算法:

取一个固定值P,把字符串看作p进制数,并分配一个大于0的数值,代表每种字符,一般来说,我们分配的数值都有远小于p。

一般来说p取131或13331,此时hash的冲突率极低,只要hash值相同,我们就认为原字符串是相等的。

实战演练:

对于一串字符串:asdfasdjgjkhasd
选取p为131我们用1代表a,2代表b,以此类推,那么我们对于每一个位都用p进制表示出来,比如;第一位是a,也就是1,这样1就可以表示a这个一个字符的字符串,那么如果字符串是as怎么表示呢,与数学的进制相同
(例:比如1101是二进制的数,怎么表示成十进制的数呢,一位的1可以用十进制的1表示,那么11怎么表示呢,用12+1即可,那么110怎么表示呢,用二位的再加上最后的0即可,则为(1 2+1)2+0,那么1101呢,以此类推,再把前三位的数2+1即可;则((1*2+1)*2+0)*2+1)=11;
理论上讲,这相当于把前面n位的数左移m位,加上m位数,就能变成n位后面再加m位的值了,上面的例子就是n和m为1 的时刻;

操作:

1.我们可以通过左移再加数操作完成字符串的hash值的求取;求得以后即可以通过比较hash值的大小来判断是否相等;
2.对于一个长字符串可以通过前缀和求任意一段的字符的hash值,首先用前缀和表示出任意一位p进制的基数,即p的n次方,求字符串arr[l~r]的哈希值的时候即可用(f [ r ] - f [ l - 1 ] * p [ r - l + 1 ]);(f里面是 f[ 0 ~ i ] 的字符串的哈希值);这样即可实现该操作,然后再通过1操作即可实现目的;

例题

题目链接

#include<unordered_set>
#include<iostream>
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
const int N=1010;
char s[1000100];
unsigned long long f[1000010],p[1000010];
int main(){
    scanf("%d",s+1);
    int n=strlen(s+1),q;
    scanf("%d",&q);
    p[0]=1;
    for(int i=1;i<=n;i++){
        f[i]=f[i-1]*131+s[i]-'a'+1;
        p[i]=p[i-1]*131;
    }
    for(int i=0;i<q;i++){
        int l1,l2,r1,r2;
        cin>>l1>>r1>>l2>>r2;
        if(f[r1]-f[l1-1]*p[r1-l1+1]==f[r2]-f[l2-1]*p[r2-l2+1]){
            puts("Yes");
        }
        else puts("No");
    }
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值