2.2字符串中的哈希.pdf
字符串中的哈希
主讲人:邓哲也
字符串中的哈希
假设有n个长度为L的字符串,问其中最多有几个字符串
是相等的。
直接比较两个长度为L的字符串是否相等时间复杂度是
O(L)的。
22
因此需要枚举O(n)对字符串进行比较,时间复杂度O(nL)
如果我们把每个字符串都用一个哈希函数映射成一个整数。
问题就变成了查找一个序列的众数。
时间复杂度变为了O(nL)
字符串中的哈希
一个设计良好的字符串哈希函数可以让我们先用O(L)的时
间复杂度预处理,之后每次获取这个字符串的一个子串的哈
希值都只要O(1)的时间。
这里我们就重点介绍BKDRHash
BKDRHash
BKDRHash的基本思想就是把一个字符串当做一个k进制数
来处理。
intk=19,M=1e9+7;
intBKDRHash(char*str){
intans=0;
for(inti=0;str[i];i++)
ans=(1LL*ans*k+str[i])%M;
returnans;
}
BKDRHash
假设字符串s的下标从1开始,长度为n。
ha[0]=0;
for(inti=1;i=n;i++)
ha[i]=(ha[i-1]*k+str[i])%M;
我们知道ha[i]就是s[1..i]的BKDRHash
那么现在询问s[x..y]的BKDRHash,你能快速求解吗?
BKDRHash
注意到ha[y]=s[1]ky-1+s[2]ky-2+…+s[x-1]ky-x+1+
s[x]ky-x+…+s[y]
注意到ha[x-1]=s[1]kx-2+s[2]kx-3+…+s[x-1]
而我们要求的s[x..y]的哈希值为s[x]ky-x+…+s[y]
可以发现s[x..y]=ha[y]-ha[x-1]ky-x+1
因此我们预处理出ha数组和k的幂次,每次询问s[x..y]
的哈希值,只要O(1)的时间。
边学边练
阿轩在纸上写了两个字符串,分别记为A和B。利用在数据结构与算法课
上学到的知识,他很容易地求出了“字符串A从任意位置开始的后缀子串”
与“字符串B”匹配的长度。
不过阿轩是一个勤学好问的同学,他向你提出了Q个问题:在每个问题中,
他给定你一个整数x,请你告诉他有多少个位置,满足“字符串A从该位
置开始的后缀子串”与B匹配的长度恰好为x。
例如:A=aabcde,B=ab,则A有aabcde、abcde、bcde、cde、de、e这6个
后缀子串,它们与B=ab的匹配长度分别是1、2、0、0、0、0。因此A有4
个位置与B的匹配长度恰好为0,有1个位置的匹配长度恰好为1,有1个位
置的匹配长度恰好为2。
1≤N,M,Q≤200000
边学边练
核心问题就是:给定两个字符串A,B。
求出A的每个后缀子串和B的最长公共前缀。
标准做法是扩展KMP,时间复杂度线性。
我们来用Hash试试看。
边学边练
前面已经提到,我们可以用O(n)预处理O(1)处理出一个子
串的哈希值。
求字符串A[i..n]与字符串B[1..m]的最长公共前缀?
二分!
二分长度mid
计算出A[i..i+mid-1]和B[1..mid]的哈希值,比较是否
相等。
因此时间复杂度是O(logn)的!
边学边练
llgetha(intx,inty){
returnha[y]-ha[x-1]*p[y-x+1];