【字符串】字符串哈希

单哈希

以下是字符串哈希的 C++ 代码模板,基于 ​多项式滚动哈希​ 实现,支持快速计算子串哈希值,适用于子串匹配、重复检测等问题:

#include <vector>
#include <string>
using namespace std;

class StringHash {
private:
    using LL = long long;
    vector<LL> prefix;   // 前缀哈希数组
    vector<LL> power;    // 存储 base 的幂次
    LL base, mod;        // 哈希参数(基数,模数)

public:
    // 初始化哈希参数,可自定义 base 和 mod
    explicit StringHash(const string& s, LL base = 131, LL mod = 1e9 + 7) 
        : base(base), mod(mod) {
        int n = s.size();
        prefix.resize(n + 1);
        power.resize(n + 1);
        power[0] = 1; // base^0 = 1
        
        // 预处理前缀哈希和幂次数组
        for (int i = 0; i < n; ++i) {
            prefix[i + 1] = (prefix[i] * base % mod + s[i]) % mod;
            power[i + 1] = power[i] * base % mod;
        }
    }

    // 计算子串 s[left..right] 的哈希值(闭区间,0-based)
    LL getHash(int left, int right) {
        // 公式:hash = (prefix[right+1] - prefix[left] * power[right-left+1]) % mod
        LL res = (prefix[right + 1] - prefix[left] * power[right - left + 1] % mod) % mod;
        return res < 0 ? res + mod : res; // 保证结果非负
    }
};

/* 使用示例 */
int main() {
    string s = "abcde";
    StringHash sh(s); // 默认参数 base=131, mod=1e9+7
    
    // 计算 "bc" 的哈希值(对应闭区间 [1,2])
    LL hash_bc = sh.getHash(1, 2);
    
    return 0;
}

image

image
自然溢出法

class NaturalStringHash {
private:
    using ULL = unsigned long long;
    vector<ULL> prefix, power;
    ULL base;
public:
    NaturalStringHash(const string& s, ULL base = 131) : base(base) {
        int n = s.size();
        prefix.resize(n + 1);
        power.resize(n + 1);
        power[0] = 1;
        for (int i = 0; i < n; ++i) {
            prefix[i + 1] = prefix[i] * base + s[i];
            power[i + 1] = power[i] * base;
        }
    }

    ULL getHash(int left, int right) {
        return prefix[right + 1] - prefix[left] * power[right - left + 1];
    }
};

image

双哈希

以下是双哈希模板的 C++ 实现,通过组合两组不同的哈希参数来降低哈希冲突的概率

#include <iostream>
#include <vector>
#include <string>

using namespace std;
using LL = long long;

class DoubleHash {
private:
    struct SingleHash {
        vector<LL> prefix, power;
        LL base, mod;

        // 单个哈希的初始化
        SingleHash(const string& s, LL base, LL mod) : base(base), mod(mod) {
            int n = s.size();
            prefix.resize(n + 1);
            power.resize(n + 1);
            power[0] = 1;
            for (int i = 0; i < n; ++i) {
                prefix[i + 1] = (prefix[i] * base % mod + s[i]) % mod;
                power[i + 1] = (power[i] * base) % mod;
            }
        }

        // 获取单个哈希值
        LL get(int l, int r) {
            LL res = (prefix[r + 1] - prefix[l] * power[r - l + 1] % mod) % mod;
            return res < 0 ? res + mod : res;
        }
    };

    // 使用两组不同的 base 和 mod 参数
    SingleHash h1, h2;

public:
    // 构造函数(可自定义参数)
    explicit DoubleHash(const string& s, 
        LL base1 = 131, LL mod1 = 1e9 + 7, 
        LL base2 = 13331, LL mod2 = 1e18 + 3)
        : h1(s, base1, mod1), h2(s, base2, mod2) {}

    // 返回双哈希值(pair形式)
    pair<LL, LL> get(int l, int r) {
        return {h1.get(l, r), h2.get(l, r)};
    }
};

/* 使用示例 */
int main() {
    string s = "abcabc";
    DoubleHash dh(s);

    // 计算子串 [0, 2]("abc")的双哈希
    auto hash1 = dh.get(0, 2);

    // 计算子串 [3, 5]("abc")的双哈希
    auto hash2 = dh.get(3, 5);

    // 当且仅当两个哈希值都相等时,认为子串相同
    if (hash1 == hash2) {
        // 两个子串匹配成功
    }

    return 0;
}

image

posted @ 2025-03-05 11:44  Tshaxz  阅读(68)  评论(0)    收藏  举报
Language: HTML