字符串hash算法

感觉没找到什么例题,但也是一个重要的思考方式,复杂度O(1)。

经典问题:如果有一个庞大的字符串数组,然后给你一个单独的字符串,让你从这个数组中查找是否有这个字符串并找到它。

字符串hash是指将一个字符串s映射为一个,使得该整数可以尽可能唯一的代表也就是唯一标识。换言之,如果两个字符的hash值相同那么我们可以认为两者相同。

字符串hasn函数有很多种,下面这篇博客有做比较:
各种字符串Hash函数比较
总而言之,反而简单的BKDRHash无论是在实际效果还是编码实现中,效果都是最突出的,一般也只讲这种。

首先我们定一个 素数 seed (常见 31,131,313,3131,3131313 等等) ,则 hash值就等于 每一个字符的Ascll码乘以seed的n次方 累加 之后再对哈希数组大小取余得到余数就是hash值,n就是位数,size 就是hash数组的大小。
贴一段打比赛用的到的代码:

ull BKDRHash(char *s){
    
    
	ull seed=131,key=0;
	while(*s)	key=key*seed+(*s++);
	return key%mod;
}

公式一:hash[i] = ( hash[i-1]*p + idx(s[i]) )%mod

基于字符串hash函数,可以求字符串的任何一个子串的hash值:
公式二:hash[l…r] = ( ( hash[r] - hash[l-1] * p^(r-l+1) ) %mod + mod ) % mod。

typedef unsigned long long ull;
const int maxn=1e6+7;
const int seed=131;
char str[maxn];
ull h[maxn],p[maxn];//h数组是求前缀哈希值,p数组是求进制的i次幂
//求一段区间的哈希值
ull get(int l,int r){
    
    	return h[r]-h[l-1]*p[r-l+1];	}

int main(){
    
    
    scanf("%s",str+1);
    int n=strlen(str+1);
    p[0]=1;
    for(int i=1;i<=n;i++){
    
    
        h[i]=h[i-1]*seed+str[i]-'a'+1;
//注意:“+1”不能省,否则“agh”与“gh”表示用一个数,也可以写h[i]=h[i-1]*seed+str[i];  
        p[i]=p[i-1]*seed;
    }
}

一道哈希例题

注意点:
1、一般数据在1e6的,就不要用mod了,能用ull就用ull,可能有误差。
2、多个字符串,p[maxn]可以预处理。
3、字符串中输出一些字符,用后一个区间哈希值+前一个区间哈希值*后一个区间长度(l-r+1)即可。

猜你喜欢

转载自blog.csdn.net/weixin_45606191/article/details/107673496