0 拉宾-卡普算法

来自wiki
在计算机科学中,拉宾-卡普算法(英語:Rabin–Karp algorithm)或卡普-拉宾算法(Karp–Rabin algorithm),是一种由理查德·卡普与迈克尔·拉宾于1987年提出的、使用散列函数以在文本中搜寻单个模式串的字符串搜索算法单次匹配。该算法先使用旋转哈希以快速筛出无法与给定串匹配的文本位置,此后对剩余位置能否成功匹配进行检验。此算法可推广到用于在文本搜寻单个模式串的所有匹配或在文本中搜寻多个模式串的匹配。

1 算法本身主要思想

  • 1 朴素匹配: text = "abcdefabc"长度为n,去匹配长度为m的模式串abc,

    • 具体做法则是找出所有长度为m的字串,然后为每一个m字串去匹配模式串abc,复杂度为O(nm)
  • 2 使用拉宾-卡普算法改进:
    • 2.1 找出了所有长度为m的字串,那么能不能在O(1)的时间内去判断两个长度为m的字串是否相等?
    • 2.2 很自然的想到hash,那么如何计算一个字串的hash?比如abc,使用26进制编码(因为text中只有小写字母)即可: hash(abc) = 26^2 * (‘a’ - ‘a’) + 26^1 * (‘b’ - ‘a’) + 26^0 * (‘c’ - ‘a’);
    • 2.3 很容易注意到上面,若字符串很长,比如100,那么hash值就有26^100,显然太大,需要取模,取模后带来问题,造成hash碰撞,则需要散列,常用的有拉宾指纹,我们可以使用两个不同模算出来一对hash值当做为一个整体hash,降低hash碰撞的概率
    • 2.4 那么计算hash明明需要读取模式串,复杂度为O(m)啊?
      • 那是因为对于text,我们只需要计算第一个长度为m的字串的hash,后面的字串hash都可以通过O(1)时间获取:
      • 直接看图:,图片来源
      • 解释: ft_i为第i个字串的hash,在o(1)时间内得到ft_i+1的方案就如图所示,或者看如下例子的代码的check函数

例子

1044. 最长重复子串 longestDupSubstring

1 题目

https://leetcode-cn.com/problems/longest-duplicate-substring/

2 解题思路

  • 0 使用官方思路: rabin-karp + binarySearch
  • 1 这里需要使用rabin-karp算法,在长度为n的text中寻找长度为m的模式串,其复杂度为o(m),然后用二分法去确定最长字符串的长度,故整体复杂度为O(n logn),拉宾-卡普算法参考:https://xychen5.github.io/2021/12/28/rabinKarp/

typedef pair<long long, long long> pll;
class Solution {public:static constexpr int big = 1000000006;// cal: a^m % mod, when m = 1000, a = 26, there will be overflowlong long pow(int a, int m, int mod) {long long ans = 1;long long curNum = a;while(m > 0) {if(m % 2 == 1) {ans = ans * curNum % mod;       // overflowif(ans < 0) { ans += mod;}}curNum = curNum * curNum % mod;// overflowif(curNum < 0) {curNum += mod;}m /= 2;}return ans;}// return st of substr with len = lenint check(vector<int>& arr, int len, int a1, int a2, int mod1, int mod2) {int n = arr.size();long long powA1 = pow(a1, len, mod1);long long powA2 = pow(a2, len, mod2);long long hashA1 = 0, hashA2 = 0;// cout << "d2.5" << endl;// cal hash of the first substr// hashA1 = arr[0] * a1^(len-1) + arr[1] * a1^(len-2) + ... + arr[len-1]for(int i = 0; i < len; ++i) {hashA1 = (hashA1 * a1 % mod1 + arr[i]) % mod1;hashA2 = (hashA2 * a2 % mod2 + arr[i]) % mod2;hashA1 += hashA1 >= 0 ? 0 : mod1;hashA2 += hashA2 >= 0 ? 0 : mod2;}// cout << "d3" << endl;// calculate all substr's hash with len = lenset<pll> seen;seen.emplace(hashA1, hashA2);for(int st = 1; st <= n - len; ++st) {// cout << "d4" << endl;// O(1) to cal next hashhashA1 = (hashA1 * a1 % mod1 - arr[st - 1] * powA1 % mod1 + arr[st + len - 1]) % mod1;hashA2 = (hashA2 * a2 % mod2 - arr[st - 1] * powA2 % mod2 + arr[st + len - 1]) % mod2;hashA1 += hashA1 >= 0 ? 0 : mod1;hashA2 += hashA2 >= 0 ? 0 : mod2;// before cursubstr, there is a same oneif(seen.count(make_pair(hashA1, hashA2))) {return st;}seen.emplace(hashA1, hashA2);}return -1;}string longestDupSubstring(string s) {int n = s.size();// code the stringvector<int> arr(n);for(int i = 0; i < n; ++i) {arr[i] = s[i] - 'a';}// two random base and modsrand((unsigned)time(NULL));int a1 = random()%75 + 26;int a2 = random()%75 + 26;int mod1 = random()%(INT_MAX - big) + big;int mod2 = random()%(INT_MAX - big) + big;// bin search the length of longest dup substrint l = 1, r = n - 1;int finalSt = -1, finalLen = -1;while(l <= r) {// m represents target len// int m = (l + r) / 2; int m = l + (r - l + 1) / 2; // cout << "d1" << endl;int st = check(arr, m, a1, a2, mod1, mod2);// cout << "d2" << endl;if(st != -1) {finalLen = m;l = m + 1;finalSt = st;} else {r = m - 1;}}return finalLen == -1 ? "" : s.substr(finalSt, finalLen);}
}

拉宾-卡普算法详解以及示例[rabin-karp]相关推荐

  1. NMS(非极大值抑制)算法详解与示例

    一.NMS是什么? NMS(non maximum suppression)即非极大值抑制,广泛应用于传统的特征提取和深度学习的目标检测算法中. NMS原理是通过筛选出局部极大值得到最优解. 在2维边 ...

  2. 归并排序算法详解及示例

    归并排序 归并排序算法是在分治算法的基础上设计出来的一种排序算法,它可以可以对指定的序列完成升序,(由小到大),或降序(由大到小),时间复杂度为 O ( n l o g n ) O(nlogn) O( ...

  3. 加密系列 | 3DES加密和解密算法详解代码示例

    3DES的在Java的实现与DES类似,如下代码为3DES加密算法.CBC模式.PKCS5Padding填充方式的加密解密结果,参考代码如下所示: import java.security.Key;i ...

  4. 【机器学习】【隐马尔可夫模型-3】后向算法:算法详解+示例讲解+Python实现

    0.前排提示 csdn有些数学公式编辑不出来,所以本博用容易书写的表达式来表示专业数学公式,如: (1)  在本博客中用α<T>(i)来表示 (2)在本博客中用[i=1, N]∑来表示 注 ...

  5. 【目标检测】Faster RCNN算法详解

    转载自:http://blog.csdn.net/shenxiaolu1984/article/details/51152614 Ren, Shaoqing, et al. "Faster ...

  6. Faster RCNN算法详解

    Ren, Shaoqing, et al. "Faster R-CNN: Towards real-time object detection with region proposal ne ...

  7. AdBoost算法详解

    AdBoost算法详解 1 算法简介 1.2AdaBoost特点 1.3Bagging与AdaBoost区别 2AdaBoost算法步骤 3 AdaBoost的数学定义 4 推广到多分类 算法引入: ...

  8. 20200118:(leetcode)最长回文子串(中心扩展算法详解及思考)

    最长回文子串(中心扩展算法详解及思考) 题目 中心扩展算法详解 代码实现 题目 给定一个字符串 s,找到 s 中最长的回文子串.你可以假设 s 的最大长度为 1000. 示例 1: 输入: " ...

  9. NEAT(NeuroEvolution of Augmenting Topologies)算法详解与实践(基于NEAT-Python)

    NEAT(NeuroEvolution of Augmenting Topologies)算法详解与实践(基于NEAT-Python) NEAT算法详解 NEAT算法概述 NEAT编码方案 结构突变 ...

  10. html5 游戏 算法,JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解【圆形情况】...

    JS/HTML5游戏常用算法之碰撞检测 包围盒检测算法详解[圆形情况] 发布时间:2020-10-10 13:42:43 来源:脚本之家 阅读:95 作者:krapnik 本文实例讲述了JS/HTML ...

最新文章

  1. Coinbase调查发现,BCH上市前没有发生不当交易
  2. 使用FragmentTabHost和ViewPager实现仿微信主界面侧滑
  3. 触发一个断点_一个补丁引发的RCE: 对CVE20191208的深入分析
  4. 云存储领域的那些安全难题与解决途径
  5. 【David Silver强化学习公开课】-3:DP
  6. 超好用的Windows管理器工具
  7. 【CentOS Linux 7】实验1【Linux文件目录管理】
  8. js - (初中级)常见笔试面试题
  9. CSS实现响应式布局(自动拆分几列)
  10. c#ovalshape_【原创】C# 实现拖拉控件改变位置与大小(SamWang)(附源代码下载)
  11. 《Python入门到精通》流程控制语句
  12. FreeRTOS源码分析与应用开发07:事件标志组
  13. Win7下使用U盘安装Ubuntu16.04双系统图文教程(亲测)
  14. ROS-Academy-for-Beginners 替换自己的地图模型
  15. 【JAVA笔记——术】JAVA LIST DEL遍历方式研究
  16. Python脚本覆盖率分析方法介绍
  17. [转载]Mapx常见问题
  18. 第三讲 地理空间数据的组成与特征
  19. llq考试 圣诞欢乐赛 (第二发)
  20. Vue+Less换肤方案

热门文章

  1. 成功学大师枭哥搞砸了,听懂掌声!
  2. 已解决:虚拟机安装windows server 2012 出现“找不到任何设备驱动程序。请确保安装介质包含正确的驱动程序”
  3. 程序员如何提高影响力2.0
  4. 3GPP 5G 常用协议规范下载整理
  5. 网线的交叉线和直通线原理
  6. 【杂学笔记-表观遗传学-updating】
  7. Android网络请求三篇
  8. 模式识别技术是人工智能的基础技术,模式识别技术的发展潜力
  9. 27 | 风控系统:如何从海量业务数据中,挖掘黑灰产?
  10. APM 页面加载耗时校准