关于字符串哈希的一点总结


字符串哈希


  1. 定义 f ( s ) f(s) f(s),表示字符串 s s s映射到整数的函数。 f f f为哈希函数。

  2. 哈希函数有两个性质

    1. 在 Hash 函数值不一样的时候,两个字符串一定不一样;
    2. 在 Hash 函数值一样的时候,两个字符串不一定一样(但有大概率一样,且我们当然希望它们总是一样的)。
  3. Hash 函数值一样时原字符串却不一样的现象我们成为哈希碰撞。

  4. 定义哈希函数公式等于(定义 l e n ( s ) len(s) len(s)表示字符串 s s s的长度) f ( s ) = ∑ i = 1 l e n ( s ) i n t ( s [ i ] ) ∗ b a s e l e n ( s ) − i % M f(s)=\sum_{i=1}^{len(s)}int(s[i])*base^{len(s)-i}\%M f(s)=i=1len(s)int(s[i])baselen(s)i%M简单来说,比如字符串abc,(其中我们令a=1,依次往后推)我们定义 f ( s ) = ( b a s e 3 ∗ 1 + b a s e 2 ∗ 2 + b a s e 1 ∗ 3 ) % M f(s)=(base^3*1+base^2*2+base^1*3)\%M f(s)=(base31+base22+base13)%M可以类比二进制,这里是base进制。

  5. 这里 M M M需要一个质数,哈希碰撞的概率为 ( l − 1 ) / M (l-1)/M (l1)/M所以应该尽可能选择大的模数。

  6. 代码实现(这里使用unsigned long long 来实现取模,c++自带的unsigned long long自动取模 2 63 − 1 2^{63}-1 2631,可以看到哈希冲突的概率基本为零。)

#define unsigned long long ull
ull Hash[N],poww[N],base[N];
string s;
ull base=233333//自己想怎么选就怎么选,选个质数
void init()
{
	Hash[0] = 0;
	poww[0] = 1;
	upd(i, 1, len)
	{
		Hash[i] = Hash[i - 1] * base + s[i] - 'a';
	}
	upd(i, 1, len)poww[i] = poww[i - 1] * base;
}
ull querry(int l, int r)
{
	return Hash[r] - Hash[l - 1] * (poww[r - l + 1]);
}


注意一下代码的细节。针对查询操作。比如我们要对比两个字符川在[L,R]区间是不是一样的。由于 f ( s ) f(s) f(s)函数的性质,哈希[L,R]区间的函数值 v a l = f ( r ) − f ( l ) ∗ b a s e r − l + 1 val=f(r)-f(l)*base^{r-l+1} val=f(r)f(l)baserl+1

为什么呢。比如abcd的哈希值

f ( s = = a b c d ) = b a s e 4 ∗ a + b a s e 3 ∗ b + b a s e 2 ∗ c + b a s e 1 ∗ d f(s==abcd)=base^{4}*a+base^{3}*b+base^{2}*c+base^{1}*d f(s==abcd)=base4a+base3b+base2c+base1d

如果我们计算区间[2,3]的哈希值, f ( s = = a b c ) = b a s e 3 ∗ a + b a s e 2 ∗ b + b a s e 1 ∗ c f(s==abc)=base^{3}*a+base^{2}*b+base^{1}*c f(s==abc)=base3a+base2b+base1c

然后是 f ( s = = a ) = b a s e 1 ∗ a f(s==a)=base^{1}*a f(s==a)=base1a那么区间[2,3]的哈希值就等于 f ( s = = a b c ) − f ( s = = a ) ∗ b a s e 2 = b a s e 3 ∗ a + b a s e 2 ∗ b + b a s e 1 ∗ c − b a s e 1 ∗ a ∗ b a s e 2 = b a s e 2 ∗ b + b a s e 1 ∗ c f(s==abc)-f(s==a)*base^{2}=base^{3}*a+base^{2}*b+base^{1}*c-base^{1}*a*base^{2}=base^{2}*b+base^{1}*c f(s==abc)f(s==a)base2=base3a+base2b+base1cbase1abase2=base2b+base1c

这就是哈希字符串bc的哈希值。也就是 f ( b c ) = = f ( r ) − f ( l ) ∗ b a s e r − l + 1 = = f ( s = = a b c ) − f ( s = = a ) ∗ b a s e 2 f(bc)==f(r)-f(l)*base^{r-l+1}==f(s==abc)-f(s==a)*base^{2} f(bc)==f(r)f(l)baserl+1==f(s==abc)f(s==a)base2

依据这个性质,我们能够对比任意等长字符串是不是同一个字符传。

入门题目 :https://www.luogu.com.cn/problem/P3370、

1.值得注意的是,尽管这样做哈希冲突的概率极小,但仍然有可能。所以可以使用两个哈希函数。选取不同的base即可。不放心还可以同时选取不同的base和模数。然后每一次比较哈希值的时候,两个同时比较。只有两个同时向邓,才能表示这两个字符串的哈希值相等。
2.不一定只有字符串才能用这种哈希,只要是区间对比是不是一样的题目,或者其他变形题目,都可以用以上的方法,进行哈希然后O(1)复杂度判断是否相等。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
字符串哈希算法是一种将字符串映射为数字的算法,常用于字符串的比较和匹配。在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 ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值