字符串哈希

字符串哈希

哈希:哈希可以理解为一种映射关系(或者可以理解为一种函数关系),在数字哈希里面是数字到数字的映射,在字符串哈希里是字符串到数字的映射,这种巧妙的映射关系保证了哈希算法在处理某些问题时具有高效性。
在字符串哈希为字符串到数字的映射关系。
我们假设一种映射关系为字符串到P进制的数的映射关系(P是任意的),那么就有了如何映射的问题:
在映射完成后要保证能完成一系列的字符串查找,比较,删除等操作,所以必须保证这种映射关系是一一映射的,不能有冲突(这也是字符串哈希和数字哈希的一大区别,对于数字哈希我们有专门的处理冲突的手段,因为应用范围的不一样,所以字符串哈希我们不会处理冲突),为了让冲突的最小化,所以我们这里取P = 131 or 13331,并且将字符串映射到 2 64 2^{64} 264范围内的数字在这时的冲突几率非常小。
总结: p = 131 or 1331, 在 2 64 2^{64} 264范围内的数字映射

字符串前缀哈希: 要想处理出来字符串任意区间内的hash, 我们首先要处理出来所有的前缀hash,例如:ABCDE我们先处理出来h[1]代表A的hash,h[2]代表B的·······以此类推,处理办法:进制的求算公式:
例如十进制的数字:145:P = 10.
1 ∗ 1 0 2 + 4 ∗ 10 + 5 ∗ 1 0 0 1*10^2+4*10+5*10^0 1102+410+5100 总结公式为下列:
a × P 4 + b × P 3 + c × P 2 + d × P 1 + e × P 0 a×P ^4+b×P ^3+c×P ^2+d×P ^1+e×P ^0 a×P4+b×P3+c×P2+d×P1+e×P0
要处理某一个前缀的hash值,要把字符串当成一个P进制的数,然后每一位的字母的ASCII值就代表这一位的数字,则abcde的hash值为上述式子
注解 :观察上式可得:存在指数爆炸的情况,所以有可能会超出我们要求的范围,想到了取模的操作,但是如果我们定义一个unsigned long long的形式,他超出的部分会自动削减掉,就相当于了取模的操作,所以以这种操作来简化取模操作。

如果要处理某区间[l, r]上的hash,那么就要用到进制运算的技巧
我们只需要知道h[l - 1] and h[r]即可求得[l, r]的hash值
其实我们要求的这个段上的hash值就是[l, r]这段上的P进制表示,所以要用到移位的运算
例如
在这里插入图片描述
在这里插入图片描述
把他处理成这种形式极为成功,处理的原理如下:

上面的数字是hash[r],下面的是hash[l - 1]
在这里插入图片描述
我们要求的就是中间标出来的那一段,显然我们是需要对hash[l - 1]进行移位,把他移到和hash[r]对头的位置,先找出来他俩的阶数之差为3,样例是在10进制下的情况,那么 h a s h [ l − 1 ] × 1 0 3 = 123000 hash[l - 1] ×10^3 = 123000 hash[l1]×103=123000,在和123456做差,得到的就是要求的区间上的hash值,即[l, r]这段上的P进制表示
公式如下: H a s h [ L , R ] = ( H a s h [ R ] − H a s h [ L − 1 ] × P R − L + 1 ) Hash[L, R]=(Hash[R]−Hash[L−1]×P ^{R−L+1} ) Hash[L,R]=(Hash[R]Hash[L1]×PRL+1)
acwing题干:字符串哈希
代码:

#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ULL;
const int N = 100010, P = 13331;
ULL h[N], p[N];
char str[N];
int n, m;

ULL get(int l, int r){
    return h[r] - h[l - 1] * p[r - l + 1];
}
int main(){
    cin >> n >> m >> str + 1;
    p[0] = 1;
    for(int i = 1; i <= n; i ++ ){
        p[i] = p[i - 1] * P;
        h[i] = h[i - 1] * P + str[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;
}
  • 9
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 6
    评论
字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++中,可以使用字符串哈希算法来加速字符串的比较操作。 引用\[1\]中的代码示例展示了一个使用字符串哈希算法的C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。其中,哈希值的计算使用了前缀和数组和幂运算。 引用\[2\]中的解释指出,使用字符串哈希的目的是为了比较字符串时不直接比较字符串本身,而是比较它们对应映射的数字。这样可以将子串的哈希值的时间复杂度降低到O(1),从而节省时间。 引用\[3\]中的代码示例也展示了一个使用字符串哈希算法的C++代码。该代码使用了前缀和数组和字符串数组来存储字符串,并通过计算哈希值来比较两个子串是否相等。与引用\[1\]中的代码类似,哈希值的计算也使用了前缀和数组和幂运算。 综上所述,字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在C++中,可以使用前缀和数组和幂运算来计算字符串哈希值,并通过比较哈希值来判断两个子串是否相等。 #### 引用[.reference_title] - *1* [C++算法题 # 33 字符串哈希](https://blog.csdn.net/weixin_44536804/article/details/123425533)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [字符串哈希(c++)](https://blog.csdn.net/qq_41829492/article/details/120980055)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [AcWing 841. 字符串哈希(C++算法)](https://blog.csdn.net/YSA__/article/details/108453403)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值