字符串匹配——RabinKarp算法
字符串匹配——RabinKarp算法
给定主串T和模式串P,返回P在T中首次出现的位置,如果P不存在于T中,返回-1。
这样的问题就是字符串匹配问题,这里给出RabinKarp算法的思想。
设主串T的长度为n,模式串P的长度为m。
主串匹配起始位置s从0到n-m,计算出T[s..s+m-1]的对应值,与P[0…m-1]的对应值进行比较,如果相同,则匹配成功。不同,则s右移一位,也就是计算出T[s+1…s+m]的对应值。
对应值的计算方法可以称作简单的指纹算法。
RabinKarp算法中的指纹算法是基于hash函数的。
其原理为 h = f % q,假设q=5,hash(12)= 12 % 5 = 2
hash函数的性质:
- if hash(s1) ≠ hash(s2) then s1 ≠ s2
- 但是hash(s1) = hash(s2)不意味着s1 = s2
模运算的性质:
- (a + b) % q = (a % q + b % q) % q
- (a * b) % q = ((a % q) * (b % q)) % q
假设字母表大小为d,hash因子为q,主串为T,长度为n,当前起始位置为s,模式串为P,长度为m,fp为P的指纹值,ft为T当前的指纹值。
预处理:
- fp = (P[m - 1] + d * (P[m - 2] + d * (P[m - 3] + … + d * ((P[1] + d * (P[0] % q)) % q)…) % q
- ft = (T[m - 1] + d * (T[m - 2] + d * (T[m - 3] + … + d * ((T[1] + d * (T[0] % q)) % q)…) % q
ft的迭代过程(右移一位):
- ft = (ft - T[s] * 10m−110^{m - 1}) * 10 + T[s + m]) % q
伪代码
假设字母表大小为d
RabinKarp(T, P)
01 q <- a prime larger than m or less than the machine word length / d
02 c <- d^(m-1) mod q // run a loop multiplying by d mod q
03 ft <- 0; fp <- 0
04 for i <- 0 to m-1 // preprocessing
05 ft <- (d * ft + T[i]) mod q
06 fp <- (d * fp + P[i]) mod q
07 for s <- 0 to n - m // matching
08 if fp = ft then // run a loop to compare strings
09 if P[0...m-1] = T[s...s+m-1] return s
10 else ft <- ((ft - T[s]*c)*d + T[s+m]) mod q
11 return -1
实现代码
生成字母表
// 字母表
int alphaBet[maxNum];
// 字母表字母个数,也就是d进制
int d;
// 生成字母表,返回字母表字母个数
int markAlphaBet(string T, string P) {// 初始化字母表memset(alphaBet, 0, sizeof(alphaBet));int d = 0;for(int i = 0; i < T.length(); i++) {if(!alphaBet[T[i]]) {alphaBet[T[i]] = d++;}}for(int i = 0; i < P.length(); i++) {if(!alphaBet[P[i]]) {alphaBet[P[i]] = d++;}}return d;
}
RabinKarp算法
const int prime = 9999991;
int rabinKarp(string T, string P) {// 字符串长度int n = T.length();int m = P.length();// 计算d^(m-1) mod qint c = 1;for(int i = 0; i < m - 1; i++) {c = (d * c) % prime;}// 初始化int ft = 0;int fp = 0;// 预处理,计算T[0...m-1]和P[0...m-1]的hash值for(int i = 0; i < m; i++) {ft = (d * ft + alphaBet[T[i]]) % prime;fp = (d * fp + alphaBet[P[i]]) % prime;}// 匹配for(int i = 0; i <= n - m; i++) {// hash值相同if(ft == fp) {// 判断字符串T[i...i+m-1]与P[0...m-1]是否相等for(int j = 0; j < m; j++) {if(T[i + j] != P[j]) {break;}if(j == m - 1) {return i;}}} else {// 计算T[i+1...i+m]的hash值ft = ((ft - alphaBet[T[i]] * c) * d + alphaBet[T[i + m]]) % prime;}}return -1;
}
测试主程序
#include <iostream>
#include <cstring>using namespace std;const int maxNum = 1000 + 5;// 字母表
int alphaBet[maxNum];
// 字母表字母个数,也就是d进制
int d;
// 生成字母表,返回字母表字母个数
int markAlphaBet(string T, string P) {// 初始化字母表memset(alphaBet, 0, sizeof(alphaBet));int d = 0;for(int i = 0; i < T.length(); i++) {if(!alphaBet[T[i]]) {alphaBet[T[i]] = d++;}}for(int i = 0; i < P.length(); i++) {if(!alphaBet[P[i]]) {alphaBet[P[i]] = d++;}}return d;
}const int prime = 9999991;
int rabinKarp(string T, string P) {// 字符串长度int n = T.length();int m = P.length();// 计算d^(m-1) mod qint c = 1;for(int i = 0; i < m - 1; i++) {c = (d * c) % prime;}// 初始化int ft = 0;int fp = 0;// 预处理,计算T[0...m-1]和P[0...m-1]的hash值for(int i = 0; i < m; i++) {ft = (d * ft + alphaBet[T[i]]) % prime;fp = (d * fp + alphaBet[P[i]]) % prime;}// 匹配for(int i = 0; i <= n - m; i++) {// hash值相同if(ft == fp) {// 判断字符串T[i...i+m-1]与P[0...m-1]是否相等for(int j = 0; j < m; j++) {if(T[i + j] != P[j]) {break;}if(j == m - 1) {return i;}}} else {// 计算T[i+1...i+m]的hash值ft = ((ft - alphaBet[T[i]] * c) * d + alphaBet[T[i + m]]) % prime;}}return -1;
}/**
IN
at the thought of
thoughOUT
7
**/
int main() {// 主串和模式串string T, P;while(true) {// 获取一行getline(cin, T);getline(cin, P);d = markAlphaBet(T, P);int res = rabinKarp(T, P);if(res == -1) {cout << "主串和模式串不匹配。" << endl;} else {cout << "模式串在主串的位置为:" << res << endl;}}return 0;
}
输出数据
at the thought of
though
模式串在主串的位置为:7
abcdefg
gfedcba
主串和模式串不匹配。
fgdajhkfhjaskdlfgbyue
yue
模式串在主串的位置为:18
frajlkfajsdlkfgjkljkleg
jsd
模式串在主串的位置为:8
aaaaaaaaaaaaaaa
a
模式串在主串的位置为:0
算法分析
- if q 是素数, hash函数将会使m位字符串在q个值中均匀分布
- 因此,仅有s个轮换中的每第q次才需要匹配指纹(匹配需要比较O(m) 次)
- 期望运行时间(如果q > m):
- 生成字母表:O(n + m)
- 预处理:O(m)
- 外循环:O(n - m)
- 所有内循环:n−mqm=O(n−m)\frac{n-m}{q}m = O(n - m)
- 总时间:O(n + m)
- 最坏运行时间:O(nm)
字符串匹配——RabinKarp算法相关推荐
- 字符串匹配 - RK算法
名称来由 RK 算法的全称叫 Rabin-Karp 算法. 它是由两位发明者 Rabin 和 Karp 的名字来命名的算法. 实现思路 BF算法的实现思路是对主串n中的每一个连续子串n1,都与模式串m ...
- 字符串匹配 RK 算法总结
背景 RK算法是通过比较字符串的哈希值来实现字符串匹配,其核心思想是把字符串转换为 N 进制的数字. 本文主要是学习和记录下其实现思想,在日常项目中字符串查找使用 string 的 find 函数即可 ...
- 字符串匹配--Sunday算法 1
字符串匹配(查找)算法是一类重要的字符串算法(String Algorithm).有两个字符串, 长度为m的haystack(查找串)和长度为n的needle(模式串), 它们构造自同一个有限的字母表 ...
- kmp算法详解php,php中字符串匹配KMP算法实现例子
KMP算法是一个比较高级的算法了,加了改进了,下面我们来在php中实现KMP算法,希望例子对各位同学会带来帮助哦. kmp算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J. ...
- 字符串匹配——BMH算法
字符串匹配--BMH算法 给定主串T和模式串P,返回P在T中首次出现的位置,如果P不存在于T中,返回-1. 这样的问题就是字符串匹配问题,这里给出BMH算法的思想. 设主串T的长度为n,模式串P的长度 ...
- 【超详细图解】字符串匹配Boyer-Moore算法:文本编辑器中的查找功能是如何实现的?
关于字符串匹配算法有很多,之前我有讲过一篇 KMP 匹配算法:图解字符串匹配 KMP 算法,不懂 kmp 的建议看下,写的还不错,这个算法虽然很牛逼,但在实际中用的并不是特别多.至于选择哪一种字符串匹 ...
- 两个字符串匹配度算法
在工作过程中,需要用到两个字符串匹配度算法,网上参考一些资料,写了一个匹配度算法类,项目中用到了而且效果很不错,今天给大家分享. 可以直接复制到你的项目中,就一个调用函数,非常简单. public c ...
- C++实现字符串匹配KMP算法
文章目录 1. 概述 2. 代码实现 3. 代码测试 1. 概述 Kmp算法的介绍及思想参阅下面两篇文章: 字符串匹配KMP算法 算法)通俗易懂的字符串匹配KMP算法及求next值算法 2. 代码实现 ...
- 字符串匹配 KMP算法
问题描述:字符串匹配即查找待匹配字符串(模式串)p在主串s中的位置.一般处理这种问题往往采用简单粗暴的方法--暴力匹配法.所谓暴力匹配法,就是对主串s的每一个字符与要匹配的字符串p的每个字符进行逐一匹 ...
最新文章
- 安装apr和tomcat-native优化tomcat
- [转载]日历设计之重复事件规则设计
- 十天学会ASP.net
- 实战SSM_O2O商铺_20【商铺编辑】View层开发
- MySQL利用存储过程清除所有表中的所有记录
- 含有运算符的STRING得到计算结果,类似JS的EVAL
- 计算机网络技术超文本,网络协议确定了计算机网络传递和管理信息的规范,其中HTTP属于()A、超文本传输协议B、传输控制协...
- java实体类属性非空判断工具类
- 一起学习C语言:函数(二)
- 计算机组成原理944考试,郑州大学2019年硕士研究生入学考试 《944计算机组成原理》考试大纲...
- 逻辑删除用户后 用户名重复怎么办?
- python数据分析学什么意思_什么是python数据分析
- c++实验总结_史上最全场景文字检测资源合集(70篇重要论文 + 15个开源代码 + 176个实验结果 + 1305个统计信息)...
- 快手分身多开黑屏脚本
- css3 的filer 功能
- FC4下安装plog快速指南(plog版本:1.01)
- python读取edi_对python .txt文件读取及数据处理方法总结
- python 今日头条 微头条_今日头条的入门,其实就是‘微头条’
- Tencent QQ皮肤图像文件格式Gft转png或bmp源代码
- 2018版 自考 计算机网络原理 04741 考试大纲
热门文章
- 使用OmniDB数据库管理工具,管理Oracle/MariaDB/PostgreSQL等关系型数据库
- 【sql那些事】时间处理的一揽子事
- 【Python爬虫】网络爬虫的“盗亦有道”
- linux安装包管理(未完待续)
- hexo博客添加暗色模式_我如何将暗模式添加到我的网站
- soa面向服务体系结构_服务和面向微服务的体系结构简介
- dagger2 注入_如何使用Dagger 2在您的应用程序中实现依赖注入
- mongodb python 大于_5、Python操作MongoDB
- mysql 本地登录失败 - 已授权
- 解决freeswitch ICE 获取RTP地址时间过长的问题