目的:判断目标串(T串)中是否含有模式串(P串)。

失配

T t0 t1 t2 …… tk tk+1
P p0 p1 p2 …… pk
由于字符串T和P第一个不相等的字符出现在位置k,所以两字符前k个字符是相等的,也说明两串在位置k处失配。

失效函数

定义:记录字符串P中各个字符之间关系的函数。

定义域:自变量 j 的取值范围是P在“失配”前匹配的字符个数,定义域为0~len(P)-1(len(P)为P的字符串长度)。
例如:P = caatcat,失效函数的定义域为 j ∈ {0,1,2,3,4,5,6}。

值域:k ∈ {x | 0 ≤ x <j },且k为满足**p0p1…pk = pj-kpj-k+1…pj**的最大正整数。
若k不存在,则失效函数的取值为-1。

例:以 P = caatcat 的失效函数为例作表。
j = 0:0 ≤ k<0,k不存在,f(0) = -1;
j = 1:0 ≤ k<1,k = 0, p0 ≠ p1(‘c’ ≠ ‘a’),k不满足条件故不存在,f(1) = -1;
j = 2:k = 0、1,p0 ≠ p2且p0 p1 ≠ p1p2,k不满足条件故不存在,f(2) = -1;
j = 3:k = 0、1、2,p0 ≠ p3且p0 p1 ≠ p2p3且p0 p1p2 ≠ p1p2p3,k不满足条件故不存在,f(3) = -1;
j = 4:k = 0、1、2、3,p0 = p4且p0 p1 ≠ p3p4且p0 p1p2 ≠ p2p3p4且p0 p1p2p3 ≠ p1p2p3p4,k=0满足条件,f(4) = 0;
j = 5:k = 0、1、2、3、4,p0 ≠ p5且p0 p1 = p4p5且p0p1p2≠ p3p4p5且p0p1p2p3≠ p2p3p4p5以及p0p1p2p3p4 ≠ p1p2p3p4p5,k = 1满足条件,f(5) = 1;
同理可求f(6) = -1;
失效函数:

j 0 1 2 3 4 5 6 7
p(j) c a a t c a t
f (j) -1 -1 -1 -1 0 1 -1
mpNext[j] / f(j-1)+1 -1 0 0 0 0 1 2 0

失配函数 f (j) 仅与模式P有关,与目标T无关,所以只要是同一个P,失效函数就适用。

MP匹配

长串在短串某个字符匹配成功时向前移动一个位置

失配情况发生在模式P的第j位
j = 0: 让目标T的指针前进一位,模式P的起始比较地址为p0
j ≠ 0: 目标T的指针不发生回溯,仍指向失配的位置,模式P的起始比较地址为pf(j-1)+1

mp算法是时间复杂度为O(m+n)1
MP模板
#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
void preMP(const char* x, int m, int mpNext[]) {int i, j;i = 0;j = mpNext[0] = -1;while (i < m) {while (j > -1 && x[i] != x[j])j = mpNext[j];mpNext[++i] = ++j;//mpNext(j)=f(j-1)+1}
}
void MP(string p, string t) {int m = p.length();int n = t.length();//模式串长度大于目标串即找不到 if (m > n) {cout << "unsuccessful match!" << endl;return;}/*c_str()用法:将string转换为c的字符串类型 详解:https://blog.csdn.net/qq_29493173/article/details/100043142  */ const char* x = p.c_str();const char* y = t.c_str();//i是模式串P的指针位置 j是目标串T的指针位置 int i = 0, j = 0;/*mpNext[]存储的是失配发生时,下一轮P的起始比较地址;因为存储的是P,数组大小比P长度略大即可*/int mpNext[m+1];//为mpNext[]赋值 preMP(x, m, mpNext);//T的指针没到末尾就一直寻找 while (j < n) {//指针指向位置的元素不同,且不为P首元素,P的指针将指向下一个索引位置 while (i > -1 && x[i] != y[j])i = mpNext[i];//若两指针指向元素相同,一齐往后移动1i++;j++;//找到完整P串输出index if (i >= m) {cout << "index at:" << j-i << endl;i = mpNext[i];//可继续找下一个P串的index } }
}
int main() {fiostring t = "ctcaatcacaatcat";string p = "caatcat";MP(p, t);
}

KMP

KMP算法与MP非常相像,用kmpNext[ ]表对P中符合要求的加标边际进行标识。

u表示P、T匹配相同的一段子串,v表示失配移动后匹配到子串u的某一部分后缀,i处的“a”与j+i处的“b”失配。

符合要求:(简单来说就是对MP的移动进一步筛选处理)
①偏移后的v是可以匹配到u中某个后缀的一个最长前缀。
v后面的字符c和u后面的字符a不同(因为a与b失配)

kmpNext表的建立可以在mpNext表的基础之上,分为四种情况,其中1 ≤ j ≤ m-1:

  1. 如果mpNext[j] = 0 且 pj = p0,则令kmpNext[j] = -1;
  2. 如果mpNext[j] = 0 且 pj ≠ p0,则令kmpNext[j] = 0;
  3. 如果mpNext[j] ≠ 0 且 pj ≠ pmpNext[j],则令kmpNext[j] = mpNext[j];
  4. 如果mpNext[j] ≠ 0 且 pj = pmpNext[j],则令 j 替换成mpNext[j],直到情况转换为前三种,进而递归求解kmpNext[j];

仍以caatcat为例求出kmpNext表:

j 0 1 2 3 4 5 6 7
p(j) c a a t c a t
mpNext[j] -1 0 0 0 0 1 2 0
kmpNext[j] -1 0 0 0 -1 0 2 0
KMP模板
#include<bits/stdc++.h>
#define fio ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
void  preKMP(const char* x, int m, int kmpNext[]) {int i = 0, j;j = kmpNext[0] = -1;while (i < m) {while (j > -1 && x[i] != x[j])j = kmpNext[j];i++;j++;/*与mp不同的地方*/if (x[i] == x[j])kmpNext[i] = kmpNext[j];else kmpNext[i] = j; }
}
void kmp(string p, string t) {int n = t.length();int m = p.length();if (m > n) {cout << "find unsuccesfully"<< endl;return;}//i短串,j长串 int i = 0, j = 0, kmpNext[m+1];const char* x = p.c_str();const char* y = t.c_str();preKMP(x, m, kmpNext);while (j < n) {while (i > -1 && x[i] != y[j])i = kmpNext[i];i++;j++;if (i >= m) {cout << "index at:" << j-i << endl;i = kmpNext[i];}}
}
int main() {fiostring t = "ctcaatcacaatcat";string p = "caatcat";kmp(p, t);
}

  1. P字符串的长度为m,T字符串长度为n ↩︎

字符串匹配(一)—— KMP / MP相关推荐

  1. 字符串匹配的KMP算法和C语言代码,不需要思考就能理解

    KMP算法用于判断一个字符串是否包含另一个字符串,如果包含就返回脚标.其实KMP算法本身特别简单,我看了几篇本章都号称简单易懂,结果看得我云里雾里,直到我看到了阮一峰:字符串匹配的KMP算法,才真正看 ...

  2. [算法系列之二十六]字符串匹配之KMP算法

    一 简介 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法).KMP算法的关键是利 ...

  3. 字符串匹配(KMP 算法 含代码)

    主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知 ...

  4. php随机匹配算法,字符串匹配的KMP算法+PHP实现

    1. 前言 看了阮一峰的字符串匹配的KMP算法,写得很好,推荐看看. 不过我想自己写个例子描述一下这个算法,顺便写个PHP实现,于是有了这篇博文. 2. 概述 [来自维基百科] 字符串搜索算法 字符串 ...

  5. 三十五、字符串匹配问题--KMP算法

    一.暴力匹配算法实现字符串匹配 如果用暴力匹配的思路,并假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有: 如果当前字符匹配成功(即 str1[i] == str2[j]) ...

  6. 字符串匹配的KMP算法(转)

    转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字符串匹配是计算 ...

  7. POJ 3461 字符串匹配(KMP / 哈希(有推导))

    文章目录 1. 题目 1.1 题目链接 1.2 题目大意 2. Accepted代码 2.1 KMP解法 2.2 哈希法(有推导过程) 1. 题目 1.1 题目链接 http://poj.org/pr ...

  8. 字符串匹配之KMP算法详解

    kmp算法又称"看毛片"算法,是一个效率非常高的字符串匹配算法.不过由于其难以理解,所以在很长的一段时间内一直没有搞懂.虽然网上有很多资料,但是鲜见好的博客能简单明了地将其讲清楚. ...

  9. 字符串匹配问题 ----- KMP算法

    题意: 任意给定一段字符串str("123abc123abc00abc") 再输入一个关键字key("abc") 要求返回str中包含key的所有子串的头下标 ...

  10. 【转载】字符串匹配的KMP算法

    转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 其他参考:htt ...

最新文章

  1. C++ 和 Java,你选哪个? | 每日趣闻
  2. 写给我的2015—开启工作新旅程
  3. php扇形分布图,PHP制作3D扇形统计图以及对图片进行缩放操作实例
  4. java 读utf-8 xml_用Java和UTF-8編碼生成有效的XML。
  5. DL之DNN之BP:神经网络算法简介之BP算法/GD算法之不需要额外任何文字,只需要八张图讲清楚BP类神经网络的工作原理
  6. 微服务架构下,解决数据一致性问题的实践 1
  7. 六十三、栈在括号匹配和表达式求值中的应用
  8. boost::hana::extend用法的测试程序
  9. 三星Nexus S刷回官方4.0.4教程
  10. 演示对sys用户和普通用户进行审计的示例
  11. 工作任务:解决双主控丢配置的问题
  12. 【云计算的1024种玩法】10分钟轻松设置出 A+ 评分的 HTTP/2 网站
  13. 创业者需要广泛了解市场中相关产品的基本情况
  14. BUG类算法研究分析
  15. 【机器学习】Softmax Regression算法原理与java实现
  16. 20套高品质的 Mobile Web 界面 PSD 素材免费下载
  17. Codeforces Round #584 (Div. 1 + Div. 2)
  18. linux系统剪切,Linux 系统裁剪
  19. Laravel查询构造器的pluck方法第一个参数可选类型array的问题
  20. 数据分析应该怎么做?

热门文章

  1. IOS 创建简单表视图
  2. C语言实现二叉树-04版
  3. 收集数据至泛型Dictionary
  4. obj.href 与 obj.getAttribute(href)的区别
  5. 每个前端工程师都应该去了解的前端面试题总结(一)
  6. 数字滤波器(六)--设计FIR滤波器
  7. 物联网专题--基于APP Inventor的BLE蓝牙4.0数据通信
  8. 4015-基于递归的折半查找(C++)
  9. 移动硬盘备份linux系统盘,将Ubuntu Linux系统放到你的移动硬盘
  10. 东方通 启动服务访问不到_使用金万维宽带通动态域名服务实现速达3000异地访问...