哈希表 Hash

哈希表
  • 一般哈希
    在这里插入图片描述
    拉链法模板
  int h[N], e[N], ne[N], idx;

    // 向哈希表中插入一个数
    void insert(int x)
    {
        int k = (x % N + N) % N;
        e[idx] = x;
        ne[idx] = h[k];
        h[k] = idx ++ ;
    }

    // 在哈希表中查询某个数是否存在
    bool find(int x)
    {
        int k = (x % N + N) % N;
        for (int i = h[k]; i != -1; i = ne[i])
            if (e[i] == x)
                return true;

        return false;
    }

开放寻址法模板

 int h[N];

    // 如果x在哈希表中,返回x的下标;如果x不在哈希表中,返回x应该插入的位置
    int find(int x)
    {
        int t = (x % N + N) % N;
        while (h[t] != null && h[t] != x)
        {
            t ++ ;
            if (t == N) t = 0;
        }
        return t;
    }
  • 字符串哈希

Step 1. 预处理出所有字符串前缀的哈希值: h[ i ] = h[i - 1] × \times × P + str[ i ]
Step 2. 求任一子串的哈希值:h[ L~R ] = h[ R ] - h[ L - 1] × \times × P R+L-1
如何定义某个前缀的哈希值?
①把字符窜看成一个P进制的数,将这个数转化为十进制数;②最后将这个数mod Q,即可把所有子串映射到 0 ~ Q-1
Tips:
①不要把字符映射为0 (eg.把A的值映射为0,则"AAAAA"所有前缀哈希值都为0),ASCII码为0的字符是’\0’ (字符串结束标志)一般不会出现
②当P = 131 || P = 13331、Q = 2 64 ==> 哈希冲突概率最小
③用 unsigned long long 存储哈希表,溢出相当于对 2^64 取模,省略了手动运算(在C++中int溢出是undefined behavior,是否会取模取决于编译器。unsigned int溢出是define behavior,在溢出时会自动取模。)

字符串哈希模板

typedef unsigned long long ULL;
ULL h[N], p[N]; // h[k]存储字符串前k个字母的哈希值, p[k]存储 P^k mod 2^64

// 初始化
p[0] = 1;
for (int i = 1; i <= n; i ++ )
{
    h[i] = h[i - 1] * P + str[i];
    p[i] = p[i - 1] * P;
}

// 计算子串 str[l ~ r] 的哈希值
ULL get(int l, int r)
{
    return h[r] - h[l - 1] * p[r - l + 1];
}
  • 二维哈希

二维哈希:从这篇博客学到的,真的写的很好捏

①首先, 按照一维哈希表预处理出每一行的哈希值:h[ i ] [ j ] 即第 i 行中(1, j)子串的哈希值 h[ i ] = h[i - 1] × \times × P1 + str[ i ] (P1 = 131)
然后,把每一行看作一个纵坐标上的点,于是又可以转换成以为哈希来处理 h[ i ][ j ] += h[i - 1][ j ] * P2 (P2 = 233)
③求(x1, y1)到(x2, y2)子矩阵的哈希值:ask(x1, y1, x2, y2) = h[x2][y2] - h[x2][y1-1] × \times ×p1[y2 - y1 + 1] - h[x1 - 1][y2] × \times ×p2[x2 - x1 + 1] - h[x1 - 1][y1 - 1] × \times ×p1[y2 - y1 + 1 ] × \times ×p2[x2 - x1 + 1]

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zlq070707

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值