字符串哈希入门

说得通俗一点,字符串哈希实质上就是把每个不同的字符串转成不同的整数

为什么会有这样的需要呢?很明显,存储一个超长的字符串和存储一个超大但是能存的下的整数,后者所占的空间会少的多,但主要还是为了方便判断一个字符串是否出现过,这是最基础的部分。

当然也很容易想到,如果有不同的字符串转成同一个整数,那么区分功能就基本废掉 ,所以我们需要一个算法把每个字符串转成唯一的整数。所以字符串哈希算法就应运而生,哈希算法的难点也就在于如何构造一个合适的Hash函数来满足我们的需求。

下面就简单介绍几种字符串哈希的基本方法。

基本哈希方法

一般地,给定一个字符串 \(S=s_1s_2s_3s_4...s_n\),令\(idx(x)=x-'a'+1\),当然,直接(int)x(用它的ASCll码)也一样。

自然溢出法

这种方法是利用数据结构unsigned long long的范围自然溢出:即当存储的数据大于unsigned long long的存储范围时,会自动mod \(2^{64}-1\),就不用mod其他质数来保证唯一性了。

Hash公式

unsigned long long Hash[n]
hash[i]=hash[i−1]∗p+idx(s[i]);

注意:这里的p一定要是个质数,不然可能无法保证唯一性。

单Hash法

相当于自然溢出法没有了自动取模的操作,所以需要自己进行取模操作。但是这种Hash方法在模数较小的时候的稳定性不一定得到保证,所以在这个方面不如其他方法。

Hash公式

hash[i]=(hash[i−1])∗p+idx(s[i])%mod;

注意:这里的\(p\)和\(mod\)都是质数,且满足\(p<mod\)。最好在选取的时候把\(p\)和\(mod\)的值取大一点。

举例

如取\(p=13,mod=101\),对字符串\(abc\)进行Hash

hash[0]=1;
hash[1]=(hash[0] × 13 + 2)%101=15;
hash[2]=(hash[1] × 13 + 3)%101=97;

所以最终字符串\(abc\)的hash值就是97

双Hash法

其实网上很多博客讲了多Hash,但我觉得双Hash已经足够稳定了,再多一些也只是浪费时间而已。

顾名思义,双Hash就是对一个hash值用两个不同的质数进行两次\(mod\)操作,然后最后用一对数\(<hash1[n],hash2[n]>\)来表示一个字符串的哈希值,这样的一对数的重复几率加上选择较大的质数,冲突率几乎为0。

Hash方法

hash1[i]=(hash1[i−1])∗p+idx(s[i]) % mod1
hash2[i]=(hash2[i−1])∗p+idx(s[i]) % mod2

这样的哈希很安全

Hash素数的选择

为了防止冲突,要选择合适的素数,像1e9+7,1e9+9的一些素数,出题人一般会卡一下下,所以尽量选择其他的素数,防止被卡。下面是一些可供选择的素数。

上界和下界指的是离素数最近的\(2^n\)的值。

lwr upr % err prime
2^5 2^6 10.416667 53
2^6 2^7 1.041667 97
2^7 2^8 0.520833 193
2^8 2^9 1.302083 389
2^9 2^10 0.130208 769
2^10 2^11 0.455729 1543
2^11 2^12 0.227865 3079
2^12 2^13 0.113932 6151
2^13 2^14 0.008138 12289
2^14 2^15 0.069173 24593
2^15 2^16 0.010173 49157
2^16 2^17 0.013224 98317
2^17 2^18 0.002543 196613
2^18 2^19 0.006358 393241
2^19 2^20 0.000127 786433
2^20 2^21 0.000318 1572869
2^21 2^22 0.000350 3145739
2^22 2^23 0.000207 6291469
2^23 2^24 0.000040 12582917
2^24 2^25 0.000075 25165843
2^25 2^26 0.000010 50331653
2^26 2^27 0.000023 100663319
2^27 2^28 0.000009 201326611
2^28 2^29 0.000001 402653189
2^29 2^30 0.000011 805306457
2^30 2^31 0.000000 1610612741

获取子串的hash

如果我们求出一个串的Hash,就可以\(O(1)\)求解其子串的Hash值。

公式的推导太复杂...干脆直接贴上来 (绝对不是我想偷懒)

公式

若已知一个\(|S|=n\)的字符串的hash值,\(hash[i]\),\(1≤i≤n\),其子串\(sl..sr,1≤l≤r≤n\),对应的hash值为:

\[hash=((hash[r]−hash[l−1]∗p^{r−l+1})\%mod+mod)\%mod
\]

ov.

【基本算法入门-字符串哈希(Hash)】-C++的更多相关文章

  1. 字符串哈希hash

    题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...

  2. Crazy Search POJ - 1200 (字符串哈希hash)

    Many people like to solve hard puzzles some of which may lead them to madness. One such puzzle could ...

  3. 牛客练习赛33 E tokitsukaze and Similar String (字符串哈希hash)

    链接:https://ac.nowcoder.com/acm/contest/308/E 来源:牛客网 tokitsukaze and Similar String 时间限制:C/C++ 2秒,其他语 ...

  4. luoguP3370 【模板】字符串哈希 [hash]

    题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...

  5. 【CodeForces】961 F. k-substrings 字符串哈希+二分

    [题目]F. k-substrings [题意]给定长度为n的串S,对于S的每个k-子串$s_ks_{k+1}...s_{n-k+1},k\in[1,\left \lceil \frac{n}{2} ...

  6. 字符串经典的hash算法

    1 概述 链表查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但Hash链表查找的时间效率为O(1). 设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无 ...

  7. 从Hash Killer I、II、III论字符串哈希

    首先,Hash Killer I.II.III是BZOJ上面三道很经典的字符串哈希破解题.当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机 ...

  8. 字符串哈希算法(以ELFHash详解)

    更多字符串哈希算法请参考:http://blog.csdn.net/AlburtHoffman/article/details/19641123 先来了解一下何为哈希: 哈希表是根据设定的哈希函数H( ...

  9. ELFhash - 优秀的字符串哈希算法

    ELFhash - 优秀的字符串哈希算法 2016年10月29日 22:12:37 阅读数:6440更多 个人分类: 算法杂论算法精讲数据结构 所属专栏: 算法与数据结构   版权声明:本文为博主原创 ...

随机推荐

  1. Win10 鼠标右键新建菜单添加自定义文件

    1. 引言 在鼠标右键(右单机)新建菜单中添加自定义文件,例如:写字板,markdown等. 效果图: 2. 操作步骤(以Win10为例) 1. win+R输入regedit进入注册表 2. 这里以添 ...

  2. Java坑人面试题之自动装箱和拆箱后的引用数据类型和基本数据类型的计算

    在Java1.5以后的版本中,引用类型Integer和基本数据类型int之间是可以通过自动装箱和拆箱进行计算的 例如: Integer in = 1; //it means  Integer in = ...

  3. Luogu4081 USACO17DEC Standing Out from the Herd(广义后缀自动机)

    建出广义SAM,通过parent树对每个节点求出其是否仅被一个子串包含及被哪个包含. 写了无数个sam板子题一点意思都没啊 #include<bits/stdc++.h> using na ...

  4. 音视频入门-04-BMP图像四字节对齐的问题

    * 音视频入门文章目录 * BMP 图像四字节对齐 表示 BMP 位图中像素的位元是以行为单位对齐存储的,每一行的大小都向上取整为4字节(32 位 DWORD)的倍数.如果图像的高度大于 1,多个经过 ...

  5. [yarn]yarn和npm的对比

    一.简介 NPM是随同NodeJS一起安装的包管理工具,能解决NodeJS代码部署上的很多问题,常见的使用场景有以下几种: 允许用户从NPM服务器下载别人编写的第三方包到本地使用. 允许用户从NPM服 ...

  6. (四)lucene之文本域加权

    一.前言 1.1 应用场景 有时在搜索的时候,会根据需要的不同,对不同的关键值或者不同的关键索引分配不同的权值,让权值高的内容更容易被用户搜索出来,而且排在前面. 为索引域添加权是再创建索引之前,把索 ...

  7. Unable to resolve service for type 'Microsoft.AspNetCore.Http.IHttpContextAccessor'

    An unhandled exception occurred while processing the request. InvalidOperationException: Unable to r ...

  8. powerdesign中逆向工程后name和comment的互换

    powerdesign 中,将数据库中可以逆向生成pdm的结构图,比较清晰看到系统的结构, 但假如是db先行的话,一般是db中的每个列中用comment中文注释说明这列是 干什么的,但逆向工程后,会发 ...

  9. MVC的12种ActionResult介绍以及应用示例【转】

    一.介绍 1.ViewResult 表示一个视图结果,它根据视图模板产生应答内容.对应得Controller方法为View. 2.PartialViewResult 表示一个部分视图结果,与ViewR ...

  10. 关于Vue中页面(父组件)下拉,页面中的子组件加载更多数据的实现方法

    一个项目中存在很多这种情况:父组件(页面)中的子组件需要做下拉加载更多的需求,但是这个下拉到底部的动作只能通过监控页面(父组件)来完成 这就需要父子组件之间的通信,代码如下: 1. 建立一个用于父子组 ...