字符串匹配(一)—— KMP / MP
目的:判断目标串(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:
- 如果mpNext[j] = 0 且 pj = p0,则令kmpNext[j] = -1;
- 如果mpNext[j] = 0 且 pj ≠ p0,则令kmpNext[j] = 0;
- 如果mpNext[j] ≠ 0 且 pj ≠ pmpNext[j],则令kmpNext[j] = mpNext[j];
- 如果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);
}
P字符串的长度为m,T字符串长度为n ↩︎
字符串匹配(一)—— KMP / MP相关推荐
- 字符串匹配的KMP算法和C语言代码,不需要思考就能理解
KMP算法用于判断一个字符串是否包含另一个字符串,如果包含就返回脚标.其实KMP算法本身特别简单,我看了几篇本章都号称简单易懂,结果看得我云里雾里,直到我看到了阮一峰:字符串匹配的KMP算法,才真正看 ...
- [算法系列之二十六]字符串匹配之KMP算法
一 简介 KMP算法是一种改进的字符串匹配算法,由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特-莫里斯-普拉特操作(简称KMP算法).KMP算法的关键是利 ...
- 字符串匹配(KMP 算法 含代码)
主要是针对字符串的匹配算法进行解说 有关字符串的基本知识 传统的串匹配法 模式匹配的一种改进算法KMP算法 网上一比較易懂的解说 小样例 1计算next 2计算nextval 代码 有关字符串的基本知 ...
- php随机匹配算法,字符串匹配的KMP算法+PHP实现
1. 前言 看了阮一峰的字符串匹配的KMP算法,写得很好,推荐看看. 不过我想自己写个例子描述一下这个算法,顺便写个PHP实现,于是有了这篇博文. 2. 概述 [来自维基百科] 字符串搜索算法 字符串 ...
- 三十五、字符串匹配问题--KMP算法
一.暴力匹配算法实现字符串匹配 如果用暴力匹配的思路,并假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有: 如果当前字符匹配成功(即 str1[i] == str2[j]) ...
- 字符串匹配的KMP算法(转)
转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 字符串匹配是计算 ...
- POJ 3461 字符串匹配(KMP / 哈希(有推导))
文章目录 1. 题目 1.1 题目链接 1.2 题目大意 2. Accepted代码 2.1 KMP解法 2.2 哈希法(有推导过程) 1. 题目 1.1 题目链接 http://poj.org/pr ...
- 字符串匹配之KMP算法详解
kmp算法又称"看毛片"算法,是一个效率非常高的字符串匹配算法.不过由于其难以理解,所以在很长的一段时间内一直没有搞懂.虽然网上有很多资料,但是鲜见好的博客能简单明了地将其讲清楚. ...
- 字符串匹配问题 ----- KMP算法
题意: 任意给定一段字符串str("123abc123abc00abc") 再输入一个关键字key("abc") 要求返回str中包含key的所有子串的头下标 ...
- 【转载】字符串匹配的KMP算法
转自:http://www.ruanyifeng.com/blog/2013/05/Knuth%E2%80%93Morris%E2%80%93Pratt_algorithm.html 其他参考:htt ...
最新文章
- C++ 和 Java,你选哪个? | 每日趣闻
- 写给我的2015—开启工作新旅程
- php扇形分布图,PHP制作3D扇形统计图以及对图片进行缩放操作实例
- java 读utf-8 xml_用Java和UTF-8編碼生成有效的XML。
- DL之DNN之BP:神经网络算法简介之BP算法/GD算法之不需要额外任何文字,只需要八张图讲清楚BP类神经网络的工作原理
- 微服务架构下,解决数据一致性问题的实践 1
- 六十三、栈在括号匹配和表达式求值中的应用
- boost::hana::extend用法的测试程序
- 三星Nexus S刷回官方4.0.4教程
- 演示对sys用户和普通用户进行审计的示例
- 工作任务:解决双主控丢配置的问题
- 【云计算的1024种玩法】10分钟轻松设置出 A+ 评分的 HTTP/2 网站
- 创业者需要广泛了解市场中相关产品的基本情况
- BUG类算法研究分析
- 【机器学习】Softmax Regression算法原理与java实现
- 20套高品质的 Mobile Web 界面 PSD 素材免费下载
- Codeforces Round #584 (Div. 1 + Div. 2)
- linux系统剪切,Linux 系统裁剪
- Laravel查询构造器的pluck方法第一个参数可选类型array的问题
- 数据分析应该怎么做?
热门文章
- IOS 创建简单表视图
- C语言实现二叉树-04版
- 收集数据至泛型Dictionary
- obj.href 与 obj.getAttribute(href)的区别
- 每个前端工程师都应该去了解的前端面试题总结(一)
- 数字滤波器(六)--设计FIR滤波器
- 物联网专题--基于APP Inventor的BLE蓝牙4.0数据通信
- 4015-基于递归的折半查找(C++)
- 移动硬盘备份linux系统盘,将Ubuntu Linux系统放到你的移动硬盘
- 东方通 启动服务访问不到_使用金万维宽带通动态域名服务实现速达3000异地访问...