[知识点]字符串Hash
1、前言
字符串的几大主要算法都多少提及过,现在来讲讲一个称不上什么算法, 但是非常常用的东西——字符串Hash。
2、Hash的概念
Hash更详细的概念不多说了,它的作用在于能够对复杂的状态进行简单的表达,更方便的用于判重。在搜索的时候,或是动规的时候,都有过类似的做法。在实际应用中,也是非常重要的,这也就是为什么存在什么暴雪公司的Hash算法等等;加密环节也是Hash的重要之处,MD5码就是一个经典的例子。
字符串Hash的方式多式多样,重点来解释一下最简单的,最常用的。
3、BKDRHash
作为竞赛选手,BKDRHash必定是首选的!通过多种测试与研究,BKDRHash在简单Hash中是冲突量最小的一种Hash方式,处理起来也非常好理解。先看一段简短的代码:
------------------------------------------------------------------------------------------------------
#define x 131
#define MOD 1000000007
int h[MAXN];
char a[MAXN];
void getHash()
{
int len = strlen(a);
for (int i = 0; i <= len - 1; i++) h[i] = (h[i - 1] * x + a[i]) % MOD;
}
------------------------------------------------------------------------------------------------------
这种方式类似于进制数表示。对于一个字符串a的某一位i,乘上一个x^i,在x>=字符串中的字符数的情况下,Hash值和字符串必定是一一映射的,当且仅当在一一对应的情况下,我们的Hash值才有存在的含义。
但是显然的,有一个很严重的问题,倘若某个字符串规定只有10个字符,长度最长为8,则极限情况下Hash值为10^8。放入一个Hash值数组中,当然是可行的。但是在很多时候,字符串的长度和字符区域不会这么小的。这也是我最开始很困惑的地方,似乎无解的样子。这个时候,我们只能选择牺牲完美的正确性来满足条件了。
对于超过某个限度的数,我们给他取一个MOD。这样好像很逗的样子?我们简单分析一下出现重复的情况,在随机造数据求Hash值取模数1e9+7之后,冲突率为0.05%上下。在算法竞赛中,这种错误率几乎可以不计。
这也就有人问了,在非100%正确率的情况下,如果出题人丧心病狂的话,这不同样会出现用来卡你的数据?要知道,字符串Hash的灵活性是非常强的!上面代码中我们可以看出,x和MOD都是我们自己定义的,它并不取决于题目的数据(当然x是必须大于字符集的这个不用多说)。
上述代码中,我们的x设定值为131,我并不清楚为什么要用这个数,确实网上的很多做法和教程也都是131,但是其实局限性并没有这么强。只要这个数是大于等于出现的字符个数的,是都可以满足的,例如某提中提到全部为小写字母,x>=26即可。这个应该是不存在卡数据的。
关键就在于MOD的讲究。其实通过网上的,学长的各种表述,取MOD的方式也是各种花样。数值越大越好这个当然是必然的!但是在这个基础上取质数也是最好的。为什么说这个事有讲究的,可能在NOIP和一些比较基础的比赛/考试中,这个不影响;但是大考试中,如HNOI/CTSC中据说都出现过的专门卡特定MOD数的情况。比如1e9+7,1e6+7,1e9+1都是比较常见的,有些出题人故意尝试着去卡,导致某些选手分数降低。这个时候就可以花式取模了,只要是个较大的数,最好是个质数,比如你的生日之类的,如19990522之类的,谁会知道呢。
在平均情况下,采用伪随机数据,MOD<=5e6才会出现一个错误点,所以自己好好把握吧。
3、多Hash取值
我相信和我一样,许多人还是有后顾之忧,所以又出现了若干的方法使这个冲突率变得更小。因为对于算法竞赛,这个0.05%似乎不值得一提;但是对于大型工程,如软件,系统,游戏等,面对全球大量客户,不不难出现一些BUG。暴雪公司(Bilzzard)就有着自己的高效而巧妙的Hash值取法,这里不提;他们似乎对这个依旧不放心,于是还决定采取多Hash值的判断。
对于一个字符串,我们假定给他两个Hash值(BKDRHash和其他的类型,参见网上若干教程),当且仅当两个字符串的两个Hash值都是一样的,我们才认为这两个字符串相等。根据乘法原理,这已经显而易见了,冲突率就会是两个Hash方法的乘积之和,可见其量之小。
同样地,你也可以选择3个Hash,4个Hash,但是随着个数的增加,复杂度也会升高,所以一般取2~3个是足够了的。暴雪公司的设定冲突率为1:18889465931478580854784,大概是10^(-22.3)%,对一个游戏程序来说足够安全了。
4、Hash挂链
上述的多Hash取值相比挂链是要好理解一些的,暴雪公司就从来不挂链,但是作为一种方法,这里依旧要提及。Hash挂链才是真正的能够保证完美正确性的方法。同样先上一段代码。
------------------------------------------------------------------------------------------------------
vector <int> h[MAXN];
void add(int o)
{
int t = o % MOD;
for (int i = 1; i <= h[t].size(); i++)
if (h[t][i] == o) return;
h[t].push_back(o);
}
------------------------------------------------------------------------------------------------------
存放Hash值的容器为vector以节省空间,它的作用和链表一样(你也可以选择手写链表)。对于某一个数经过取模之后得到的数为t,它对应的vector为h[t]。我们将所有取模之后得到t的原值放入o,这样,可以很容易地发现是否冲突,只需要在vector中扫描一遍。
确实这个正确性是必定保证了的,但是相比之下,时间复杂度和空间复杂度似乎都不够理想,当然在能确保的情况下绝对是可以用的。
5、总结
字符串Hash,作用是无限的。KMP,SA等等,经常出现可以用字符串Hash代替的情况。
[知识点]字符串Hash的更多相关文章
- 【二分答案+智障的字符串hash】BZOJ2946-[Poi2000]公共串(Ranklist倒一达成!!!!!)【含hash知识点】
[题目大意] 给出几个由小写字母构成的单词,求它们最长的公共子串的长度. [字符串hash的小笔记] hash[i]=(hash[i-1]*p+idx(s[i]))%mod,idx为映射值,一般a.. ...
- 【BZOJ-3555】企鹅QQ 字符串Hash
3555: [Ctsc2014]企鹅QQ Time Limit: 20 Sec Memory Limit: 256 MBSubmit: 1545 Solved: 593[Submit][Statu ...
- POJ 1200 字符串HASH
题目链接:http://poj.org/problem?id=1200 题意:给定一个字符串,字符串只有NC个不同的字符,问这个字符串所有长度为N的子串有多少个不相同. 思路:字符串HASH,因为只有 ...
- LA4671 K-neighbor substrings(FFT + 字符串Hash)
题目 Source http://acm.hust.edu.cn/vjudge/problem/19225 Description The Hamming distance between two s ...
- 各种字符串Hash函数比较(转)
常用的字符串Hash函数还有ELFHash,APHash等等,都是十分简单有效的方法.这些函数使用位运算使得每一个字符都对最后的函数值产生影响.另外还有以MD5和SHA1为代表的杂凑函数,这些函数几乎 ...
- 字符串hash + 二分答案 - 求最长公共子串 --- poj 2774
Long Long Message Problem's Link:http://poj.org/problem?id=2774 Mean: 求两个字符串的最长公共子串的长度. analyse: 前面在 ...
- 字符串hash - POJ 3461 Oulipo
Oulipo Problem's Link ---------------------------------------------------------------------------- M ...
- 长度有限制的字符串hash函数
长度有限制的字符串hash函数 DJBHash是一种非常流行的算法,俗称"Times33"算法.Times33的算法很简单,就是不断的乘33,原型如下 hash(i) = hash ...
- hdu 4622 Reincarnation 字符串hash 模板题
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622 题意:给定一个长度不超过2000的字符串,之后有不超过1e5次的区间查询,输出每次查询区间中不同 ...
随机推荐
- file_get_contents带bom
$dmText = file_get_contents( AROOT .'data' . DS . 'DMType.json.php'); if(preg_match('/^\xEF\xBB\xBF/ ...
- ng-disabled 不起作用的解决办法
不知道这算不算 Angular.js 的一个bug.但搜索一番后找到了一个变通的解决办法. 业务需求是这样的, 按钮被点击一次之后就设置为禁用状态, 以阻止多次无效的点击.但现在很多框架都用 < ...
- React入门
一.引入Reactjs 方法一:直接下载相关js文件引入网页,其中react.js 是 React 的核心库,react-dom.js 是提供与 DOM 相关的功能,Browser.js 的作用是将 ...
- AM335x kernel 4.4.12 i2c eeprom AT24c02驱动移植
kernel 4.4.12 i2c eeprom AT24c02驱动移植 在kernel make menuconfig ARCH=ARM 中打开: Device Drivers ---> Mi ...
- Unity3D访问Android系统目录
file:///sdcard/Movies/3D/互动.mp4file:///storage/emulated/0/Movies/3D/互动.mp4/storage/emulated/0/Movies ...
- SpringMVC
使用注解去完成整个项目 安装spring的一个插件,则相关的提示就会出来
- .net项目中上传的图片或者文件太大 无法上传
最近做项目的时候 用户提出要上传大图片 一张图片有可能十几兆 本来用的第三方的上传控件 有限制图片上传大小的设置 以前设置的是2M 按照用户的要求 以为直接将限制图片上传大小的设置改下就可 ...
- Web服务器与数据库服务器分离 导入 Excel数据至数据库
一般情况一般项目WEB服务器与数据库均部署在一台服务器,文件上传,数据导入在一台服务器完成.web服务器与数据库服务器分离,文件上传与数据导入将分布在两台服务器或多台服务器之间.本案例为两台服务器,具 ...
- JS获取浏览器窗口大小 获取屏幕,浏览器,网页高度宽度
网页可见区域宽:document.body.clientWidth 网页可见区域高:document.body.clientHeight 网页可见区域宽:document.body.offsetWid ...
- SVN本地代码未提交而被覆盖
本地代码未提交而不小心被覆盖了,肿么办... 到回收站找到你的文件 xxx.mine,代码就可以找回来了.如果回收站没有了,那就没办法了. ---- 失而复得的感觉真好!