Rabin-Karp算法

本文详细介绍了Rabin-Karp算法,一种通过将字符串转化为哈希值进行快速匹配的字符串匹配技术,涉及哈希基数、哈希模数、逐字符计算哈希值以及避免哈希冲突的方法。
摘要由CSDN通过智能技术生成

❤️️💚💙💛🧡💜🖤🤍🧡

大家好!我是曾续缘🥰

欢迎关注💕

❤️点赞 👍 收藏 ⭐再看,养成习惯

🔥除了努力向前之外,还要记得时刻提醒自己,不要迷失方向,丢了你的初心。📚

Rabin-Karp算法是一种常用的字符串匹配算法,它的基本思想是将字符串转化为哈希值进行匹配,以达到快速匹配的目的。其核心思想是将字符串看作一个数字,通过对该数字进行哈希计算,判断其是否与模式串对应的哈希值相等。

以下是具体步骤:

  1. 定义存储结果的向量 res
  2. 获取 spattern 的长度 nm,如果 n 小于 m,则直接返回空的结果向量。
  3. 定义素数 P 和哈希模数 MOD
  4. 计算模式串 pattern 的哈希值 targetHash 和最高位权值 h。这里使用了逐个字符地计算哈希值的方法,即先初始化 targetHashh,然后依次加入 pattern 中每个字符的贡献,其中 targetHash * P + pattern[i] 表示将上一个哈希值乘以 P 并加上新字符的哈希值,% MOD 表示对哈希值取模避免溢出。
  5. 从左到右扫描字符串 s,依次计算每个子串的哈希值 curHash。同样地,使用逐个字符地计算哈希值的方法,每当加入一个新字符时,将当前的哈希值乘以 P 并加上新字符的哈希值,再对哈希值取模。为了快速地更新哈希值,同时删除子串左侧第一个字符的贡献,需要判断当前子串的长度是否大于等于 m。如果是,将左侧第一个字符对哈希值的贡献 **s[i-m] \* h** 从当前哈希值中减去即可,再对哈希值取模并保证结果非负。(**注意:**因为第一个字符的权值是最高位的权值,如果只是减去其 ASCII 码值,那相当于把第一个字符的权值忽略了,会导致计算出的哈希值偏大。因此,需要额外乘上这个权值,以保证计算出的新的哈希值是正确的。)
  6. 如果当前子串的长度恰好为 m,并且当前哈希值和目标哈希值相等,则需要进一步判断子串的确实内容是否与 pattern 相等。如果相等,将子串在 s 中的起始位置加入结果向量 res
  7. 最后返回结果向量 res
vector<int> rabinKarp(string s, string pattern) {
    vector<int> res;
    int n = s.size(), m = pattern.size();
    if (n < m) return res;

    const long long P = 131; // 取一个素数作为哈希基数
    const long long MOD = 1e9 + 7; // 取一个素数作为哈希模数

    long long targetHash = 0;
    long long h = 1;
    for (int i = 0; i < m; i++) {
        targetHash = (targetHash * P + pattern[i]) % MOD;
        h = (h * P) % MOD;
    }

    long long curHash = 0;
    for (int i = 0; i < n; i++) {
        curHash = (curHash * P + s[i]) % MOD;
        if (i >= m) {
            curHash = curHash - (s[i - m] * h) % MOD;
            if (curHash < 0) curHash += MOD;
        }
        if (i >= m - 1 && curHash == targetHash) {
            if (s.substr(i - m + 1, m) == pattern) {
                res.push_back(i - m + 1);
            }
        }
    }

    return res;
}

这里我们使用了一个素数 P 作为哈希基数,并且取了一个素数 MOD 作为哈希模数。我们首先计算出模式串的哈希值 targetHash,然后依次计算原字符串的哈希值 curHash,如果发现它与目标哈希值相等,则说明找到了一次匹配,此时可以将对应位置记录到结果数组中。为了避免哈希冲突,我们可以通过多项式哈希来计算哈希值,同时也可以通过快速幂和取模运算来提高计算效率。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值