热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

字符串匹配RabinKarp算法讲解

问题描述:Rabin-Karp的预处理时间是O(m),匹配时间O((n-m1)m)既然与朴素算法的匹配时间一样,而且还多了一些预处理时间&

问题描述:

      Rabin-Karp的预处理时间是O(m),匹配时间O( ( n - m + 1 ) m )既然与朴素算法的匹配时间一样,而且还多了一些预处理时间,那为什么我们还要学习这个算法呢?虽然Rain-Karp在最坏的情况下与朴素匹配一样,但是实际应用中往往比朴素算法快很多而且该算法的期望匹配时间是O(n)【参照《算法导论》】,但是Rabin-Karp算法需要进行数值运算,速度必然不会比KMP算法快,那我们有了KMP算法以后为什么还要学习Rabin-Karp算法呢?个人认为学习的是一种思想,一种解题的思路,当我们见识的越多,眼界也就也开阔,面对实际问题的时候,就能找到更加合适的算法。比如二维模式匹配,Rabin-Karp就是一种好的选择。

      而且Rabin-Karp算法非常有趣,将字符当作数字来处理,基本思路:如果Tm是一个长度为 |P| 的T的子串,且转换为数值后模上一个数(一般为素数)与模式字符串P转换成数值后模上同一个数的值相同,则Tm可能是一个合法的匹配。

Rabin-Karp字符串匹配算法和前面介绍的《朴素字符串匹配算法》类似,也是对应每一个字符进行比较,不同的是Rabin-Karp采用了把字符进行预处理,也就是对每个字符进行对应进制数并取模运算,类似于通过某种函数计算其函数值,比较的是每个字符的函数值。预处理时间O(m),匹配时间是O((n-m+1)m)。Rabin-Karp算法的思想:假设待匹配字符串的长度为M,目标字符串的长度为N(N>M);
首先计算待匹配字符串的hash值,计算目标字符串前M个字符的hash值;
比较前面计算的两个hash值,比较次数N
-M+1:
若hash值不相等,则继续计算目标字符串的下一个长度为M的字符子串的hash值
若hash值相同,则需要使用朴素算法再次判断是否为相同的字串;

 

We can compute p in time O(m) using Horner's rule (see Section 32.1):

p
= P[m] + 10 (P[m - 1] + 10(P[m - 2] + . . . + 10(P[2] + 10P[1]) . . . )).
The value t0 can be similarly computed
from T[1 . . m] in time O(m).To compute the remaining values t1, t2, . . . , tn-m in time O(n - m), it suffices to observe that ts + 1 can be computed from ts in constant time, sincets + 1 = 10(ts - 10m - 1T[s + 1]) + T[s + m + 1].(34.1)
For example,
if m= 5 and ts = 31415, then we wish to remove the high-order digit T[s + 1] = 3 and bring in the new low-order digit (suppose it is T[s + 5 + 1] = 2) to obtaints+1 = 10(31415 - 10000.3) + 2= 14152 .

http://net.pku.edu.cn/~course/cs101/2007/resource/Intro2Algorithm/book6/chap34.htm

以上算法很简单,但是当模式字符串P的长度达到7以后就要出错了,即使将t,p定义为long unsigned int型也解决不了大问题,也就是说上面代码没什么用。

  其中b是基数,相当于把字符串看作b进制数。这样,字符串S=s1s2s3...sn从位置k+1开始长度为m的字符串子串S[k+1...k+m]的哈希值,就可以利用从位置k开始的字符串子串S[k...k+m-1]的哈希值,直接进行如下计算:H(S[k+1...k+m])=(H(S[k...k+m-1])* b - sk*b^m + s(k+m)) mod h

    该算法的难点就在于p和t的值可能很大,导致不能方便的对其进行处理。对这个问题有一个简单的补救办法,用一个合适的数q来计算p和t的模。每个字符其实十一个十进制的整数,所以p,t以及递归式都可以对模q进行,所以可以在O(m)的时间里计算出模q的p值,在O(n - m + 1)时间内计算出模q的所有t值。参见《算法导论》或http://net.pku.edu.cn/~course/cs101/2007/resource/Intro2Algorithm/book6/chap34.htm


 

递推式是如下这个式子: 

ts+1 = (d *( ts-T[s + 1]*h) + T[s + m + 1 ] ) mod q

例如,如果d = 10 (十进制)m= 5, ts = 31415,我们希望去掉最高位数字T[s + 1] = 3,再加入一个低位数字(假定 T[s+5+1] = 2)就得到:

ts+1 = 10*(31415 - 1000*3) +2 = 14152

于是,只要不断这样计算开始位置右移一位后的字符串子串哈希值,就可以在O(n)时间内得到所有位置对应的哈希值,从而可以在O(n+m)时间内完成字符串匹配。在实现时,可以用64位无符号整数计算哈希值,并取h等于2^64,通过自然溢出省去求模运算。

typedef unsigned long long ull;
const ull b=100000007;//哈希的基数;
//a是否在b中出现
bool contain(string C,string S)
{
int m&#61;C.length(),n&#61;S.length();if(m>n) return false;//计算b的m次方ull t&#61;1;for(int i&#61;0;ib;//计算C和S长度为m的前缀对应的哈希值ull Chash&#61;0,Shash&#61;0;for(int i&#61;0;iC[i];for(int i&#61;0;iS[i];//对S不断右移一位&#xff0c;更新哈希值并判断for(int i&#61;0;i&#43;m<&#61;n;i&#43;&#43;){if(Chash&#61;&#61;Shash) return true;//S从位置i开始长度为m的字符串子串等于C&#xff1b;if(i&#43;mm];}return false;
}

滚动哈希&#xff08;Rabin-Karp算法&#xff09;

 


 

hash( txt[s&#43;1 .. s&#43;m] ) &#61; ( d ( hash( txt[s .. s&#43;m-1]) – txt[s]*h ) &#43; txt[s &#43; m] ) mod q

hash( txt[s .. s&#43;m-1] ) : Hash value at shift s.
hash( txt[s&#43;1 .. s&#43;m] ) : Hash value at next shift (or shift s&#43;1)
d: Number of characters in the alphabet
q: A prime number
h: d^(m-1)

/* Following program is a C implementation of Rabin Karp
Algorithm given in the CLRS book
*/
#include

#include
<string.h>// d is the number of characters in the input alphabet
#define d 256/* pat -> patterntxt -> textq -> A prime number
*/
void search(char pat[], char txt[], int q)
{
int M &#61; strlen(pat);int N &#61; strlen(txt);int i, j;int p &#61; 0; // hash value for patternint t &#61; 0; // hash value for txtint h &#61; 1;// The value of h would be "pow(d, M-1)%q"for (i &#61; 0; i 1; i&#43;&#43;)h &#61; (h*d)%q;// Calculate the hash value of pattern and first// window of textfor (i &#61; 0; i ){p &#61; (d*p &#43; pat[i])%q;t &#61; (d*t &#43; txt[i])%q;}// Slide the pattern over text one by onefor (i &#61; 0; i <&#61; N - M; i&#43;&#43;){// Check the hash values of current window of text// and pattern. If the hash values match then only// check for characters on by oneif ( p &#61;&#61; t ){/* Check for characters one by one */for (j &#61; 0; j ){if (txt[i&#43;j] !&#61; pat[j])break;}// if p &#61;&#61; t and pat[0...M-1] &#61; txt[i, i&#43;1, ...i&#43;M-1]if (j &#61;&#61; M)printf("Pattern found at index %d \n", i);}// Calculate hash value for next window of text: Remove// leading digit, add trailing digitif ( i M ){t &#61; (d*(t - txt[i]*h) &#43; txt[i&#43;M])%q;// We might get negative value of t, converting it// to positiveif (t <0)t &#61; (t &#43; q);}}
}
/* Driver program to test above function */
int main()
{
char txt[] &#61; "GEEKS FOR GEEKS";char pat[] &#61; "GEEK";int q &#61; 101; // A prime number
search(pat, txt, q);return 0;
}

 

 

参考资料&#xff1a;http://www.geeksforgeeks.org/archives/11937

参考资料&#xff1a;http://net.pku.edu.cn/~course/cs101/2007/resource/Intro2Algorithm/book6/chap34.htm

http://www.cnblogs.com/feature/articles/1813967.html &#xff08;翻译PKU

转:https://www.cnblogs.com/Roni-i/p/9447409.html



推荐阅读
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 本文介绍了UVALive6575题目Odd and Even Zeroes的解法,使用了数位dp和找规律的方法。阶乘的定义和性质被介绍,并给出了一些例子。其中,部分阶乘的尾零个数为奇数,部分为偶数。 ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 学习Java异常处理之throws之抛出并捕获异常(9)
    任务描述本关任务:在main方法之外创建任意一个方法接收给定的两个字符串,把第二个字符串的长度减1生成一个整数值,输出第一个字符串长度是 ... [详细]
  • 使用圣杯布局模式实现网站首页的内容布局
    本文介绍了使用圣杯布局模式实现网站首页的内容布局的方法,包括HTML部分代码和实例。同时还提供了公司新闻、最新产品、关于我们、联系我们等页面的布局示例。商品展示区包括了车里子和农家生态土鸡蛋等产品的价格信息。 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文主要解析了Open judge C16H问题中涉及到的Magical Balls的快速幂和逆元算法,并给出了问题的解析和解决方法。详细介绍了问题的背景和规则,并给出了相应的算法解析和实现步骤。通过本文的解析,读者可以更好地理解和解决Open judge C16H问题中的Magical Balls部分。 ... [详细]
  • 《数据结构》学习笔记3——串匹配算法性能评估
    本文主要讨论串匹配算法的性能评估,包括模式匹配、字符种类数量、算法复杂度等内容。通过借助C++中的头文件和库,可以实现对串的匹配操作。其中蛮力算法的复杂度为O(m*n),通过随机取出长度为m的子串作为模式P,在文本T中进行匹配,统计平均复杂度。对于成功和失败的匹配分别进行测试,分析其平均复杂度。详情请参考相关学习资源。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 3.223.28周学习总结中的贪心作业收获及困惑
    本文是对3.223.28周学习总结中的贪心作业进行总结,作者在解题过程中参考了他人的代码,但前提是要先理解题目并有解题思路。作者分享了自己在贪心作业中的收获,同时提到了一道让他困惑的题目,即input details部分引发的疑惑。 ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • 本文介绍了Java中Hashtable的clear()方法,该方法用于清除和移除指定Hashtable中的所有键。通过示例程序演示了clear()方法的使用。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • 本文整理了Java面试中常见的问题及相关概念的解析,包括HashMap中为什么重写equals还要重写hashcode、map的分类和常见情况、final关键字的用法、Synchronized和lock的区别、volatile的介绍、Syncronized锁的作用、构造函数和构造函数重载的概念、方法覆盖和方法重载的区别、反射获取和设置对象私有字段的值的方法、通过反射创建对象的方式以及内部类的详解。 ... [详细]
author-avatar
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有