【基本算法入门-字符串哈希(Hash)】-C++
字符串哈希入门
说得通俗一点,字符串哈希实质上就是把每个不同的字符串转成不同的整数。
为什么会有这样的需要呢?很明显,存储一个超长的字符串和存储一个超大但是能存的下的整数,后者所占的空间会少的多,但主要还是为了方便判断一个字符串是否出现过,这是最基础的部分。
当然也很容易想到,如果有不同的字符串转成同一个整数,那么区分功能就基本废掉 ,所以我们需要一个算法把每个字符串转成唯一的整数。所以字符串哈希算法就应运而生,哈希算法的难点也就在于如何构造一个合适的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值为:
\]
ov.
【基本算法入门-字符串哈希(Hash)】-C++的更多相关文章
- 字符串哈希hash
题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...
- Crazy Search POJ - 1200 (字符串哈希hash)
Many people like to solve hard puzzles some of which may lead them to madness. One such puzzle could ...
- 牛客练习赛33 E tokitsukaze and Similar String (字符串哈希hash)
链接:https://ac.nowcoder.com/acm/contest/308/E 来源:牛客网 tokitsukaze and Similar String 时间限制:C/C++ 2秒,其他语 ...
- luoguP3370 【模板】字符串哈希 [hash]
题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字.大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串. 友情提醒:如果真的想好好练习哈希的话,请自觉,否则请右转 ...
- 【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} ...
- 字符串经典的hash算法
1 概述 链表查找的时间效率为O(N),二分法为log2N,B+ Tree为log2N,但Hash链表查找的时间效率为O(1). 设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无 ...
- 从Hash Killer I、II、III论字符串哈希
首先,Hash Killer I.II.III是BZOJ上面三道很经典的字符串哈希破解题.当时关于II,本人还琢磨了好久,但一直不明白为啥别人AC的代码都才0.3kb左右,直到CYG神犇说可以直接随机 ...
- 字符串哈希算法(以ELFHash详解)
更多字符串哈希算法请参考:http://blog.csdn.net/AlburtHoffman/article/details/19641123 先来了解一下何为哈希: 哈希表是根据设定的哈希函数H( ...
- ELFhash - 优秀的字符串哈希算法
ELFhash - 优秀的字符串哈希算法 2016年10月29日 22:12:37 阅读数:6440更多 个人分类: 算法杂论算法精讲数据结构 所属专栏: 算法与数据结构 版权声明:本文为博主原创 ...
随机推荐
- Linux centos 7下搭建mosquitto
Centos7安装 1.网卡名改为enth0 A: vim /etc/sysconfig/grub B: 第三行添加"net.ifnames=0 biosdevname=0" ...
- C 循环统计输入的单词个数和字符长度
C 循环统计输入的单词个数和字符长度 #include <stdio.h> #include <Windows.h> int main(void) { ]; ; ; print ...
- 数据库-SQL语句练习【已完成26题,还剩35题】
练习题链接:https://www.nowcoder.com/ta/sql?page=0 错题频次表 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 1+1 1+ ...
- ASP.NET MVC或者.net Core mvc 页面使用富文本控件的 保存问题
https://blog.csdn.net/leftfist/article/details/69629394 目前在做的项目存在XSS安全漏洞! 原因是有一些页面使用了富文本编辑框,为了使得其内容可 ...
- Word文档转PDF方法探索
最近的项目中需要将Word转换为PDF文件,找了很多方法和组件,最后找到了一些方法,和大家分享. 一.使用微软官方自带转换方法 好处是写法方便,官方支持,缺点是需要在服务器上安装office,而且要配 ...
- RE:ゼロから始める AFO 生活
新建这篇博客的时候发现自己在NOI之后只发过两三篇博客,而且都基本上没什么实质性内容. 果然是巨大混混人啊. 本文承接上篇(不过好像烂尾了),旨在记录一些有趣(?)的内容. 12.23 北大集训过去好 ...
- TypeScript入门八:TypeScript的命名空间
初识命名空间(namespace指令) 命名空间与文件拆分 多重命名空间与三斜杠指令引入依赖文件 一.初识命名空间(namespace指令) TypeScript的命名空间可以说就是ES6的模块化,其 ...
- springboot项目命linux环境下命令启动
测试环境:dev nohup java -Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=1099 \-Dcom.s ...
- Hibernate-validate工具类,手动调用校验返回结果
引言:在常见的工程中,一般是在Controller中校验入参,校验入参的方式有多种,这里介绍的使用hibernate-validate来验证,其中分为手动和自动校验,自动校验可以联合spring,使用 ...
- 免安装方式的Python之VSCode环境配置
概述 本文旨在介绍免安装方式,在VSCode中搭建Python(3.73)的配置环境.至于Python是什么.它能做些什么,诸如此类的介绍均不在此文中介绍,相信能看此文的人,多多少少都会有些了解. V ...