字符串哈希(c++)

什么是字符串Hash

hash, 其实就是将一个东一映射成另一个东西, 类似Map的键值对.

那么字符串Hash, 其实就是: 构造一个数字使之唯一代表一个字符串. 但是为了将映射关系进行一一对应, 也就是, 一个字符串对应一个数字, 反之一个数字也对应一个字符串.

用字符串Hash的目的是: 如果我们要比较一个字符串, 我们不直接比较字符串, 而是比较它们对应映射的数字, 这样子就知道两个"子串"是否相等. 从而达到子串的Hash值的时间为O(1), 进而可以利用"空间换时间"来节省时间复杂度.

我们希望这是个映射是单射, 所以问题就是如何构造这个哈希函数, 使他们成为一个单射.

构造字符串Hash

假如给你一个数字1166, 形式上你只知道他是1和6的组合, 但你知道它代表的实际为:
1 * 10 ^3 + 1 * 10 ^2 + 6 * 10 ^1 + 6 * 10 ^0
同理, 给你一个字符串, 要把他转换为数字, 就可以先把每一个字符都对应一个数字, 然后把他们按照顺序乘以进制(Base) 的幂进行相加, 然后这个数可能很大, 所以一半会取余.

根据上面的理解, 其实将字符串映射成数字, 和我们平时的将一个某进制的数转换为十进制,相类似.

我们先定义以下:

给定一个字符串S = s1 s2 s3 s4 … sn, 对于每个si就是一个字母, 那我们规定idx(si) = si - ‘a’ + 1.(当然也可以直接用ASCII值)

使用Base 和 MOD(都要求是素数), 一般都是base < mod, 同时将Base 和 MOD尽量取大即可,这种情况下, 冲突(即不同字符串有相同Hash值)的概率很低.

实现方法

我们定义 Base ,而MOD对于自然溢出方法,就是 unsigned long long 整数的自然溢出(相当于MOD 是 2^{64} - 1)

#define ull unsigned long long
 
ull Base;
ull hash[MAXN], p[MAXN];
 
hash[0] = 0;
p[0] = 1;

定义了上面的两个数组,首先hash[i]表示[0,i]字符串的hash值. 而 p[i] 表示Base^i, 也就是
底的i次方.

那么对应的 Hash 公式为:
在这里插入图片描述
(类似十进制的表示,14,一开始是 0,然后 0 * 10 + 1 = 1,接着 1*10 + 4 = 14)。

例子

在这里插入图片描述
现在我们想求子串s3s4的哈希值, 不难得出s3*Base + s4, 并且从上面观察, 如果看hash[4] - hash[2]并将结果中带有s1,s2系数的项全部消掉, 就是所求. 但是由于Base的阶数, 不能直接相减消掉, 所以问题转化成将hash[2]乘以个关于Base的系数, 在做差的时候才能消除多余的项.

易得,对应系数只差一个Base@2 而 4 - 2 = 2(待求hash子串下标相减即可), 这样就不难推出公式:
hash[4] - hash[2] * Base^2
至此,可以总结出一下公式:

若已知一个S = s1s2s3…sn的字符串的Hash值, hash[i],0<=i<=n, 其中子串sl…sr对应的hash值为:
res = hash[r] - hash[l - 1] * Base^(r-l+1)

同时,hash值是要进行取MOD的:
(res = hash[r] - hash[l - 1] * Base^(r-l+1))%MOD

看起来这个式子人畜无害, 但是对于取模运算需要谨慎谨慎再谨慎, 注意到括号里的是减法, 即有可能是负数, 因此需要做如下的修正:

res = ((hash[r] - hash[l-1] * Base^(r-l+1))%MOD+MOD)%MOD
至此得到求子串的hash公式.

值得一提的, 如果需要反复对子串求解hash值, 预处理Base的n次方效果更佳. 所以才有上面用p[i] = (Base^i) % MOD, 注意也是有取余的.

  • 9
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在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 ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

善良的大铁牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值