• 字符串哈希 INnoVation


    字符串哈希

    题目

    给定一个长度为 n 的字符串,再给定 m 个询问,每个询问包含四个整数 \(l_1,r_1,l_2,r_2\),请你判断 \([l_1,r_1]\)\([l_2,r_2]\) 这两个区间所包含的字符串子串是否完全相同。字符串中只包含大小写英文字母和数字。

    思路

    利用哈希的思想,将一段字符串通过哈希函数转换为一串数字,然后通过对比两个数字是否相同,判断两个字符串是否相等。

    具体做法

    1.求字符串的哈希值

    以ABCD为例,将其视为一个P进制数,则

    $ Hash(ABCD) = A \times p^4 + B \times p^3 + C \times p^2 + D \times p^1 $

    此时,Hash值必然是一个较大的数,可能会溢出,因此需要对Q取余,即

    Hash(ABCD) = Hash(ABCD) % Q

    这里存在两个经验值

    令P = 131 或 13331,Q = 2^64时,冲突的概率会较小

    2.如何求出其中任意一段的哈希值

    假设已知Hash(ABCDE),如何求出Hash[3,5],即Hash[CDE]的值?

    $ Hash[CDE] = C \times P^3 + D \times P ^ 2 + E \times p^1 $

    $ Hash[ABCDE] = A \times P^5 + B \times p^4 + C \times p^3 + D \times p^2 + E \times p^1 $

    $ Hash[AB] = A \times P^2 + D \times P^1 $

    因此

    \(Hash[CDE] = Hash[ABCDE] - Hash[AB] \times P^3 \\ = Hash[ABCDE] - Hash[AB] \times P^{3-1+1}\)

    代码

    #include<iostream>
    using namespace std;
    const int N = 1e5 + 10;
    //ULL为64位无符号整数,使用它进行存储,相当于对2^64取余
    typedef unsigned long long ULL;
    int P = 131;
    char s[N];
    ULL h[N], p[N];
    
    int query(int l, int r){
        return h[r] - h[l - 1] * p[r - l + 1];
    }
    
    int main(){
        int n, m;
        cin >> n >> m >> (s + 1);
        p[0] = 1;
        for(int x = 1; x <= n; x++){ //求哈希值
            h[x] = h[x - 1] * P + s[x];
            p[x] = p[x - 1] * P;
        }
        while(m--){ //查询
            int l1, r1, l2, r2;
            cin >> l1 >> r1 >> l2 >> r2;
            cout << (query(l1, r1) == query(l2, r2) ? "Yes" : "No") << endl;
        }
    }
    
  • 相关阅读:
    Java知识之运算符篇
    对List取交集、联集及差集
    SQL in与exists的执行效率比较
    SQLServer数据集合的交、并、差三种集合运算
    获取外网IP
    SQL语句优化技术分析
    高并发下的获取ID解决方案
    获取数据库里面所有自增类型的最大值
    锁的概述
    项目管理心得:一个项目经理的个人体会、经验总结(转)
  • 原文地址:https://www.cnblogs.com/INnoVationv2/p/16567588.html
Copyright © 2020-2023  润新知