• Hash 学习笔记


    Hash 是一类将关键字集合映射到值集合的算法。在 OI 中的主要应用是将字符串转换为数值,提高查找的效率。

    原理

    这里将简单介绍用基数转换法实现的 Hash 函数。

    我们将需处理的 $Key$ 值看做 $b$ 进制数,然后将它转换为十进制数,再对其取模。

    例如 $Key=210867$ ,并将它看成是十三进制数 $(210867)_{13}$ ,然后将它转换为十进制数:

    $$
    (210867)_{13} = 2 imes 13 ^ 5 + 1 imes 13 ^ 4 + 8 imes 13 ^ 2 + 2 imes 13 + 7 = (772584)_{10}
    $$

    因为每个字符都有唯一的 ASCII 码,所以可以使用上面的方法将字符串转换为数值。

    设字符串 $C=c_1c_2 cdots c_m$ 从左往右由高位到低位,定义 $H(C, k)$ 为字符串起前 $k$ 位组成字符串的哈希值,$H(C) = H(C, m)$,左边为高位的定义是为了方便处理,以及压缩计算时间。

    类似快速读入的递推方法,得到:
    $$
    H(C, k+1) = H(C, k) imes b+c_{k+1}
    $$
    即:
    $$
    H(C, k) = sum_{i=1}^k (c_i imes b^{k-i})
    $$
    当我们要计算子串 $C'=c_{k+1}c_{k+2}cdots c_{k+n}$ 时联想到十进制中:
    $$
    overline{de}=overline{abcde}-overline{abc} imes10^2
    $$
    所以:
    $$
    H(C') = H(C, k+n) - H(C, k) imes b^n
    $$
    最终我们只需预处理 $b^n$和递推求出 $H(C, k)$ 后,就可以在 $O(1)$ 时间内查询字符串任意子串哈希值。

    实现

    typedef unsigned long long ULL;
    
    int bPow[lenMax+5];
    ULL sum[lenMax+5];
    
    void init(char str[], int b) {
    	bPow[0] = 1;
    	for (int i = 1; i <= lenMax; i++) {
    		bPow[i] = bPow[i - 1] * b;
    	}
    
    	int len = strlen(str);
    	sum[0] = 0;
    	for (int i = 0; i < len; i++) {
    		sum[i + 1] = sum[i] * b + (ULL)(str[i] - 'A' + 1);
    	}
    }
    
    ULL hash(int k, int n) {
    	return (ULL)sum[k + n - 1] - sum[k - 1] * bPow[n];
    }
    
  • 相关阅读:
    结合<span id="outer"><span id="inter">text</span></span>这段结构,谈谈innerHTML、outerHTML、innerText之间的区别
    字符串的方法slice、substr、substring对比
    为什么两个一样的对象,用===打印是false
    this指向
    复制对象的方法
    Promise以及async和await的用法
    前端性能优化&&网站性能优化
    P1510 精卫填海
    分解质因数
    P2648 赚钱
  • 原文地址:https://www.cnblogs.com/lcfsih/p/14351895.html
Copyright © 2020-2023  润新知