Rabin-Karp字符串哈希算法

简介: Rabin-Karp字符串哈希算法


Rabin-Karp 算法

Rabin-Karp是一种基于Hash的高效的字符串搜索算法

问题

给定长度为n的字符串s (文本串),长度为m的字符串t (模式串)

求t是否在s中出现过(t是否为s的子串)

朴素: 0(nm)

Rabin-Karp算法: 0(n + m)

思路:

计算s的每个长度为m的子串的Hash值(-一个宽度为m的滑动窗口滑过s)

检查是否与t的Hash值相等

选用的Hash函数:

把字符串看作一个b进制数(一个多项式) ,计算它(在十进制下)对p取模的值

举例:

取b= 131, p= 2^64

字符串foobar的Hash值为(a=1, b=2, f=6, o=15, r=18)

(61315 + 151314 + 15* 1313+2 1312+ 1131 + 18) mod 264

选取的b和p的值决定了Hash函数的质量

根据经验,b=131, 13331等, p为大质数,冲突概率极小

Hash值相等时可以再比对一下两个字符串 ,避免Hash碰撞问题

如何快速计算一个子串的Hash值?

s = “foobar”

先计算6个前缀子串的Hash值, 0(n):

H[i] = Hash(s[0… i-1]) = (H[i-1]*b + s[i- 1]) mod p

计算子串oba的的Hash值:

相当于b进制下两个数做减法(H[5]-H[2]b3)
fooba
-fo000
oba
Hash(s[l…r]) = (H[r + 1]- H[l] b^r-l+1)mod p
, 0(1)

实战

28.实现strStr()

https://leetcode.cn/problems/implement-strstr/

class Solution {
public:
    int strStr(string haystack, string needle) {
        int b = 131, p = 1e9 + 7;
        int n = haystack.size();
        int m = needle.size();
        vector<long long> H(n + 1, 0);
        for(int i = 1; i <= n; i++){
            H[i] = (H[i - 1] * b + (haystack[i - 1] - 'a' + 1)) % p;
        }
        long long Hneedle = 0;
        long long powBm = 1;
        for(char ch : needle) {
            Hneedle = (Hneedle * b + (ch - 'a' + 1)) % p;
            powBm = powBm * b % p;
        }
        for(int l = 1;l <= n - m + 1; l++){
            int r = l + m -1;
            if(((H[r] - H[l - 1] * powBm) % p + p) % p == Hneedle){
                return l - 1;
            }
        }
        return -1;
    }
};
class Solution {
public:
    int strStr(string haystack, string needle) {
        int b = 131;
        int n = haystack.size();
        int m = needle.size();
        vector<unsigned long long> H(n + 1, 0);
        for(int i = 1; i <= n; i++)
            H[i] = H[i - 1] * b + (haystack[i - 1] - 'a' + 1);
        unsigned long long Hneedle = 0;
        unsigned long long powBM = 1;
        for(char ch : needle) {
            Hneedle = Hneedle * b + (ch - 'a' + 1);
            powBM = powBM * b;
        }
        for (int l = 1; l <= n - m + 1; l++) {
            int r = l + m - 1;
            if(H[r] - H[l - 1] * powBM == Hneedle)
                return l - 1;
        }
        return -1;
    }
};

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

相关文章
|
1月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
3月前
|
算法
【算法】滑动窗口——找到字符串中所有字母异位词
【算法】滑动窗口——找到字符串中所有字母异位词
|
1月前
|
算法
两个字符串匹配出最长公共子序列算法
本文介绍了最长公共子序列(LCS)问题的算法实现,通过动态规划方法求解两个字符串的最长公共子序列,并提供了具体的编程实现细节和示例。
84 1
两个字符串匹配出最长公共子序列算法
|
1月前
|
存储 算法 C#
C#哈希查找算法
C#哈希查找算法
|
1月前
|
算法 安全 Go
Python与Go语言中的哈希算法实现及对比分析
Python与Go语言中的哈希算法实现及对比分析
40 0
|
1月前
|
存储 算法 C++
【算法】哈希映射(C/C++)
【算法】哈希映射(C/C++)
|
3月前
|
算法 安全 JavaScript
安全哈希算法:SHA算法
安全哈希算法:SHA算法
53 1
安全哈希算法:SHA算法
|
3月前
|
算法 Java
掌握算法学习之字符串经典用法
文章总结了字符串在算法领域的经典用法,特别是通过双指针法来实现字符串的反转操作,并提供了LeetCode上相关题目的Java代码实现,强调了掌握这些技巧对于提升算法思维的重要性。
|
3月前
|
JavaScript 算法 前端开发
国标哈希算法基础:SHA1、SHA256、SHA512、MD5 和 HMAC,Python和JS实现、加盐、算法魔改
国标哈希算法基础:SHA1、SHA256、SHA512、MD5 和 HMAC,Python和JS实现、加盐、算法魔改
490 1
|
4月前
|
缓存 负载均衡 算法
(四)网络编程之请求分发篇:负载均衡静态调度算法、平滑轮询加权、一致性哈希、最小活跃数算法实践!
先如今所有的技术栈中,只要一谈关于高可用、高并发处理相关的实现,必然会牵扯到集群这个话题,也就是部署多台服务器共同对外提供服务,从而做到提升系统吞吐量,优化系统的整体性能以及稳定性等目的。