很久以前写的。。。

今天来谈谈一种用来替代KMP算法的奇葩算法——字符串Hash

例题:给你两个字符串p和s,求出p在s中出现的次数。(字符串长度小于等于1000000)

字符串的Hash

根据字面意思,这种算法是以Hash为基础的,要Hash,就必须要将字符串转化为数字;假设这两个字符串是26个字母组成的,那么我们就可以把它们看成两个26进制的数。

但是因为字符串很长,这个数肯定是很大的,用int64(long long)存不下,那么怎么办呢?我们可以用Hash来取模,使这个数字缩小到我们可以接受的范围内。于是我们就想到了除法Hash。

Hash最重要的是解决重复,一般而言,Hash有两种方式:线性探查法、链接法,但是这两种都是以存储来解决重复的,如果要把这些字符串都存下来,空间也是不可接受,所以我们不能将这些字符串存下来以避免重复。

既然这样,我们只能求助于概率。根据生日悖论,如果取模的这个数大于等于n^2,那么冲突概率会降到50%以下,可以接受。于是我们使用100000007这个质数,概率约为50%。

这已经足够了。

两组Hash

但是,50%的概率还是有一点高。我们可以使用两组Hash来解决。

我们知道,对于任意两个数a,b,若a=b,那么无论取模的值p是多少,Hash(a)恒等于Hash(b)。也就是说,不管如何取模,两个相同的数都会被认为是相等的。所以我们可以取多个模数来降低冲突概率。如果取1个模,冲突概率为50%,那么同时取2个模的冲突概率绝对低于25%,是一个很小的概率。(一般而言,我们会取1000000007,1000000009,但是已经有被共享的数据可以冲突

Hash的加减性

仅仅是上面这些,对付例题还不够,因为我们生成一个字符串的Hash还是需要一位一位地累加,这每次会消耗O(len)的时间,很不划算。怎么办呢?

我们可以运用前缀和的思想。例如:对于如下的s

s="abcdefghij"

假设需要查找一个长度为3的字符串,那么需要比较的字符串是

abc

bcd

cde

efg

.....

可以看到,子串1(abc)和子串2(bcd)有两个字母bc是重复的,而我们之前的操作重复计算了bc的值,存在重复,这是我们优化的突破口。我们该如何避免这样的重复呢?当然是记录下来,类比片段和,片段和也是类似的通过数字的记录、加减来避免重复、快速计算。Hash的加减也和片段和差不多,只是需要注意位的对齐。

公式如下 Hash(i,j)=hash(1,j)-hash(1,i-1)*31^(j-i+1)

注释

  1. hash(i,j)表示i~j的hash值
  2. 再进行实际代码书写时,需要注意取模及负数的情况(详见代码)
  3. 这里因为字符串由小写字母构成,使用31这个进制足够大,并且31是一个质数,不像26一样容易产生重复

演示代码(Pascal)

var
s1,s2:ansistring;
n,m,i,p1,p2,ans:longint;
key1,key2,value1,value2:int64;
h1,h2,mi1,mi2:array[0..1000005] of int64;
begin
readln(s1);
readln(s2);
p1:=100000007;
p2:=100000009;
m:=length(s1);
key1:=0;
key2:=0;
for i:=1 to m do
begin
key1:=(key1*31+ord(s1[i])-96) mod p1;
key2:=(key2*31+ord(s1[i])-96) mod p2;
end;
n:=length(s2);
h1[0]:=0; mi1[0]:=1;
h2[0]:=0; mi2[0]:=1;
for i:=1 to n do
begin
h1[i]:=(h1[i-1]*31+ord(s2[i])-96) mod p1;
h2[i]:=(h2[i-1]*31+ord(s2[i])-96) mod p2;
mi1[i]:=mi1[i-1]*31 mod p1;
mi2[i]:=mi2[i-1]*31 mod p2;
end;
ans:=0;
for i:=1 to n-m+1 do
begin
value1:=(h1[i+m-1]-h1[i-1]*mi1[m] mod p1+p1) mod p1;
value2:=(h2[i+m-1]-h2[i-1]*mi2[m] mod p2+p2) mod p2;
if (value1=key1) and (value2=key2) then inc(ans);
end;
writeln(ans);
end.

KMP替代算法——字符串Hash的更多相关文章

  1. POJ3461一道kmp题,字符串Hash也可

    题目链接:http://icpc.njust.edu.cn/Problem/Pku/3461/ 代码如下: #include<cstdio> #include<string.h> ...

  2. 【字符串算法1】 再谈字符串Hash(优雅的暴力)

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法1] 字符串Hash 老版原文: RK哈希(Rabin_Ka ...

  3. poj 3461 字符串单串匹配--KMP或者字符串HASH

    http://poj.org/problem?id=3461 先来一发KMP算法: #include <cstdio> #include <cstring> #include ...

  4. 【原创】通俗易懂的讲解KMP算法(字符串匹配算法)及代码实现

    一.本文简介 本文的目的是简单明了的讲解KMP算法的思想及实现过程. 网上的文章的确有些杂乱,有的过浅,有的太深,希望本文对初学者是非常友好的. 其实KMP算法有一些改良版,这些是在理解KMP核心思想 ...

  5. 记录几个经典的字符串hash算法

    记录几个经典的字符串hash算法,方便以后查看: 推荐一篇文章: http://www.partow.net/programming/hashfunctions/# (1)暴雪字符串hash #inc ...

  6. HDU 5763 Another Meaning dp+字符串hash || DP+KMP

    题意:给定一个句子str,和一个单词sub,这个单词sub可以翻译成两种不同的意思,问这个句子一共能翻译成多少种不能的意思 例如:str:hehehe   sub:hehe 那么,有**he.he** ...

  7. 字符串Hash算法比较

    基本概念所谓完美哈希函数,就是指没有冲突的哈希函数,即对任意的 key1 != key2 有h(key1) != h(key2).设定义域为X,值域为Y, n=|X|,m=|Y|,那么肯定有m> ...

  8. 2020牛客暑期多校训练营 第二场 A All with Pairs 字符串hash KMP

    LINK:All with Pairs 那天下午打这个东西的时候状态极差 推这个东西都推了1个多小时 (比赛是中午考试的我很困 没睡觉直接开肝果然不爽 一开始看错匹配的位置了 以为是\(1-l\)和\ ...

  9. [知识点]字符串Hash

    1.前言 字符串的几大主要算法都多少提及过,现在来讲讲一个称不上什么算法, 但是非常常用的东西——字符串Hash. 2.Hash的概念 Hash更详细的概念不多说了,它的作用在于能够对复杂的状态进行简 ...

随机推荐

  1. 任意模数NTT学习笔记

    这两天有点颓,所以东西学的也很慢...这个一眼就能推出来的活生生卡了我两天.. 说几个细节: 柿子: \[f*g = (\frac{f}{M} +f\%m)*(\frac{g}{M} +g\%m) \ ...

  2. Pandas系列(一)-Series详解

    一.初始Series Series 是一个带有 名称 和索引的一维数组,既然是数组,肯定要说到的就是数组中的元素类型,在 Series 中包含的数据类型可以是整数.浮点.字符串.Python对象等. ...

  3. idea中的一些快捷键,未完待续......

    1.快速查看注释的渲染效果 在keymap中查找“Quick Documentation”并设置自己喜欢的快捷键即可 2.全局搜索 在keymap中查找“Replace in Path”并设置自己喜欢 ...

  4. VMWare的host-only/bridged/NAT连接图文介绍

    1 VMware简介 VMWare虚拟机软件是一个“虚拟PC”软件,它使我们可以在一台机器上同时运行二个或更多Windows.Linux等系统. 如果我们需要使用多个系统的话,传统的方式有两种: .使 ...

  5. IaaS,PaaS,SaaS 的区别(转)

    越来越多的软件,开始采用云服务. 云服务只是一个统称,可以分成三大类. IaaS:基础设施服务,Infrastructure-as-a-service PaaS:平台服务,Platform-as-a- ...

  6. 关于JS中的常用表单验证+正则表达式

    一.非空验证 trim:去空格(去掉前后的空格),任何字符串都可以用这个方法.写法为:if(v.trim().length==0),表示如果去掉空格后的字符串的长度为0. <body> & ...

  7. windows连接oracle数据库

    本以为很简单,结果发现还是有些坑啊 1. 安装cx_oracle pip install cx_oracle 或者用whi文件,这样你能知道版本号那些https://www.lfd.uci.edu/~ ...

  8. UDP单播,广播,多播

  9. 学习总结javascript和ajax,php,和css

    1,javascript 1,js可以获取和修改html的属性和内容: 通过什么获取? window.onload=function{ document.getElementById("xx ...

  10. niagara Workbench module import IntelliJ

    1. 在整个网络布线中使用一种布线方式,但是两端都有RJ-45 plug  的网络连线,无论是采用方式A还是方式B 端接的方式都是试用的.网络都是通用的,双绞线的顺序与RJ-45偶的引脚序号一一对应, ...