当前位置: 首页 > 编程日记 > 正文

KMP算法简单分析

定义问题

字符串匹配是这样一个问题: 对于两个包含且仅包含字母表∑中的字母的串P,T,计算出所有有效的**移进**s使得P[1..|P|] = T[s+1..s+|P|]。(|P|为P的长度)。
或者说:求出在什么位置P被T完全包含。
为了表达方便,定义m = |P|, n = |T|。P称为模式串,T称为匹配串

朴素算法

朴素算法是一种显然的方法。直接给出伪代码:

Naive-Match (P, T)m = |P|, n = |T|for i = 1..n doif P[1..m] == T thenprint i" "

朴素算法可以看成模式串紧贴匹配串滑动,尝试移进s = 1..n时能否匹配。大多数情况下,朴素算法已经可以解决问题。但是当数据极大(例如在很长的基因串中寻找一组基因)时,朴素算法的效率就显得差了。因此,科学家寻找到许多种优秀的匹配算法。这是一个常用算法时间对照表。

算法预处理匹配
朴素算法0O((n-m+1)m)
Rabin-KarpΘ(m)O((n-m+1)m)
有限自动机Θ(m∑)Θ(n)
Knuth-Morris-PrattΘ(m)Θ(n)

所有的字符串算法都很麻烦(毕竟蒟蒻)。其中KMP用处比较广。在《算法导论》里KMP的介绍是以有限自动机为基础的,然而我又看不懂,gedao了半天才大致明白KMP的思想。

KMP算法

Quote:来自 zrO matrix67 Orz

假如,A=”abababaababacb”,B=”ababacb”,我们来看看KMP是怎么工作的。我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。
- 当A[i+1]=B[j+1]时,i和j各加一;什么时候j=m了,我们就说B是A的子串(B串已经整完了),并且可以根据这时的i值算出匹配的位置。
- 当A[i+1]<>B[j+1],KMP的策略是调整j的位置(减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配(从而使得i和j能继续增加)。我们看一看当 i=j=5时的情况。
详细内容参见 http://www.matrix67.com/blog/archives/115

个人理解

我是自己推导之后才看到上面大牛的解释,真的非常通俗。所以看不懂的同学可以去哪里膜拜一下。kmp算法实在比较恶心,虽然代码秘制煎蛋,不习惯推导的童鞋直接背下来就可以了。:(语言表达能力捉急):。
ps:这里并没有使用图形辅助理解,个人认为这样更有利于理解kmp匹配原理。
kmp基于一个函数π,π表示有最大的t < i使P[1..t] = P[m-t+1..m],则t = π。或者形式化地:

π[i] = max{t | P[1..t] = P[m-t+1..m] 且 t < i}

证明一个结论,对于任意T[k-i+1..k] = P[1..i],有:

π[i] = max{t | P[1..t] = T[k-t+1..k] 且 t < i}
用反证法,假设有π[i] < x < i使得P[1..x] = T[k-x+1..k]∵ P[1..i] = T[k-i+1..k]∴ T[k-x+1..k] = P[m-x+1..m]又 P[1..t] = T[k-x+1..k]∴ P[1..x] = P[m-x+1..m]∵ x > π[i], 根据定义,矛盾
原命题得证。

这个结论将说明kmp不会错过正确解。

以及:

如果有s使T[k-s+1..k] = P[1..s],
那么有T[k-π[s]+1..k] = P[1..π[s]]。
证明很简单,根据定义等量代换即可。

这个结论将说明kmp不会找到错误解。

这些结论并不足以证明kmp的正确性,但是基本可以看出主要思想了。事实上,通过π可以省略许多无用的比较(基于第二个结论)。kmp匹配算法代码如下:

void kmp_match(int l) {// l是T的长度,pL是P的长度int q = 0;// 匹配的长度for (int i=1; i<=l; i++) {while (q > 0 && P[q+1] != T[i])q = pie[q];// 无法匹配下一位,找到可以部分匹配的最大部分,或者没有可以匹配if (P[q+1] == T[i])q++;// 下一位可以匹配if (q == pL) {// 找到printf("Shift %d >>> ", i-pL);q = pie[q];// 找下一个匹配位置}}
}

计算匹配函数π的方法:

void kmp_init() {int k = 0;pie[1] = pie[0] = 0;// 第一位不可能找到匹配for (int i=2; i<=pL; i++) {while (k > 0 && P[k+1] != P[i])k = pie[k];// 同上,自己匹配自己罢了if (P[k+1] == P[i])k++;pie[i] = k;// 记录最长匹配}
}

所谓自己匹配自己,就是π就是找到一对最大且相等的前缀和后缀,记录前缀出现位置。(基于定义)
kmp大概就是这样了,多思考就可以想通。。

kmp时间复杂度分析

kmp的复杂度为Θ(n)-Θ(m),这里用摊还分析中的聚合分析法给出一个kmp_init复杂度分析例子。我们试图证明while循环的执行次数为O(n)。
k的初值为0,而k的值增长有且只有一个途径:10行的k++。由于for循环一次k最多加一,n-1次循环之后k最多为n-1呢。由于π < i,因此while循环只会使k减少,且一次至少减少1。而k < n-1,所以while的循环次数为O(n)。不难得出kmp_init的复杂度为Θ(n)。用这种方法也可以得出kmp_match的复杂度为Θ(m)。

linux下装逼代码

装逼专用,仅售998,到linux上看看效果吧。

#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
char P[10005], T[10005];
int pL;
int pie[10005];
int readfln(char *str) {char c;int i = 0;str[0] = '\"';while (c = getchar()) {if (c!= '\n')str[++i] = c;else break;}return i;
}
void printfln(int shift,int l) {int beg = shift-5;if (shift <= 5)beg = 0;elseprintf("...");for (int i=beg+1; i<=shift; i++)putchar(T[i]);printf("\033[33m");printf("%s", P+1);printf("\033[0m");int end = shift+pL+5;if (shift+pL+5 > l)end = l;for (int i=shift+pL+1; i<=end; i++)putchar(T[i]);if (shift+pL+5 < l)printf("...");printf("\n");
}
void kmp_init() {int k = 0;pie[1] = pie[0] = 0;for (int i=2; i<=pL; i++) {while (k > 0 && P[k+1] != P[i])k = pie[k];if (P[k+1] == P[i])k++;pie[i] = k;}
}
void kmp_match(int l) {int q = 0;for (int i=1; i<=l; i++) {while (q > 0 && P[q+1] != T[i])q = pie[q];if (P[q+1] == T[i])q++;if (q == pL) {printf("Shift %d >>> ", i-pL);printfln(i-pL,l);q = pie[q];}}
}
int main() {pL = readfln(P);kmp_init();int l;while (l = readfln(T))kmp_match(l);return 0;
}

参考资料:《算法导论》

转载于:https://www.cnblogs.com/ljt12138/p/6684390.html

相关文章:

mysql查询并设置高亮_Thinkphp3.2.3设置MySql主从读写分离后,简单调用主数据库查询

图/文&#xff1a;迷神Thinkphp是一款不错的国产框架&#xff0c;使用范围广&#xff0c;应用也比较多。随着网站访问增大往往需要使用mysql主从同步功能&#xff0c;本身Thinkphp自带了主从读写分离的功能了。但是我们经常有一个场景就是某些特定的查询需要从主库进行查询&…

Microsoft Store无法联网解决方法

设置 网络 代理 关闭

MongoDB for C#基础入门

笔者这里采用的是mongoDB官网推荐使用.net驱动&#xff1a; http://mongodb.github.io/mongo-csharp-driver/2.0/getting_started/quick_tour/ 有关于MongoDB的安装读者可以参考其他的博客&#xff0c;对于基本的学习来说并不需要进行过多的配置。 创建连接 这一步骤跟ADO.NET连…

李宏毅机器学习自己的笔记(一)----------Introduction of MachineLearning

视频来源&#xff1a;李宏毅机器学习(2017)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili https://www.bilibili.com/video/av10590361/?p2 声明&#xff1a;图片均来自于视频截图 问题一&#xff1a; AI&#xff0c;机器学习 &#xff0c;深度学习关系 答&#xff1a;AI人工智能…

Unity从零开始构建能力体系 Unity Ability System

从零开始构建能力体系 你会学到什么 如何实施能力体系 如何使用用户界面工具包创建用户界面 如何使用Unity的GraphView API 如何实现保存系统 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;根…

mybatis-plus对datetime返回去掉.0_华为AI认证-TensorFlow2.0编程基础

参考《HCIA-AI2.0培训教材》《HCIA-AI2.0实验手册》认证要求&#xff1a;了解TensorFlow2.0是什么以及其特点掌握TensorFlow2.0基础和高阶操作方法熟悉TensorFlow2.0中的Keras API简介&#xff1a;TensorFlow是目前最为流行的深度学习框架&#xff0c;是人工智能领域的第一主要…

dev c++ 调试时候发生软件崩溃解决办法

dev c 调试时候发生软件崩溃解决办法 安装好dev cpp&#xff0c;准备调试的时候发现软件崩溃&#xff0c;这种情况很好解决。只要在工具菜单中点开编译选项&#xff0c;找到代码生成/优化一栏&#xff0c;将链接器的“产生调试信息”选项改为yes&#xff0c;即可

运行hadoop fs -ls 命令显示本地目录问题

2019独角兽企业重金招聘Python工程师标准>>> 运行hadoop fs -ls 命令显示本地目录问题 问题原因&#xff1a;是因为在hadoop配置文件中没有指定HDFS的默认路径 解决办法&#xff1a;有两个办法 1、使用HDFS全路径访问 hadoop fs -ls hdfs://192.168.1.1:9000/ 2…

李宏毅机器学习笔记(二)-------Why we need learn Machine Learning?

视频&#xff1a; 李宏毅机器学习(2017)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibilihttps://www.bilibili.com/video/av10590361/?p2 真是一个逗波&#xff1a; AI训练师&#xff1a; 为AI选择合适的model和损失函数。然后达到最好的功能

mixamo网站FBX模型带骨骼绑定动作库

mixamo网站FBX模型带骨骼绑定动作库&#xff0c;unity游戏各职业人物动画&#xff0c;兼容3dmax maya c4d iclone blender等主流3D软件 mixamo游戏3D模型带骨骼绑定FBX动作库 大小解压后&#xff1a;17.2G 素材获取&#xff1a;mixamo网站FBX模型带骨骼绑定动作库-云桥网

java modbus通讯协议_物联通讯协议一(Modbus)

1、Modbus是一种串行通信协议&#xff0c;是Modicon公司(现在的施耐德电气 Schneider Electric)于1979年为使用可编程逻辑控制器(PLC)通信而发表。Modbus已经成为工业领域通信协议的业界标准(De facto)&#xff0c;并且现在是工业电子设备之间常用的连接方式。2、Modbus是一种串…

hibernate3

hibernate3 &#xff08;整合到spring中的core核心配置中的hibernate3&#xff09; <!-- 基于hibernate的Session工厂 --><bean id"sessionFactory"class"org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><!…

伦理困境:人工智能浪潮与“AI威胁论”之争

首先&#xff0c;何为伦理&#xff1f; 2018年1月份的《科学与社会》报刊中有如下阐述&#xff1a; 伦理一词&#xff0c;英文为ethics&#xff0c;一词源自于希腊文的“ethos”&#xff0c;其意义与拉丁文“mores”差不多&#xff0c;表示风俗、习惯的意思。西方的伦理学发展流…

在 ASP.NET 网页中不经过回发而实现客户端回调

一、使用回调函数的好处 在 ASP.NET 网页的默认模型中&#xff0c;用户会与页交互&#xff0c;单击按钮或执行导致回发的一些其他操作。此时将重新创建页及其控件&#xff0c;并在服务器上运行页代码&#xff0c;且新版本的页被呈现到浏览器。但是&#xff0c;在有些情况下&…

李宏毅机器学习笔记(三)——Regression: output a scalar amp;amp; Gradient Descent

视频来源&#xff1a; 李宏毅机器学习(2017)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili https://www.bilibili.com/video/av10590361/?p3机器学习的目的就是找到最优函数&#xff0c;而回归的目的就是我们要找的函数的输出是一个数值。例如下面的例子&#xff0c;不管是输入怎样的…

完整的虚幻引擎超级课程:从初学者到专家

通过这个循序渐进的课程&#xff0c;学习如何像专业人士一样开发游戏和设计&#xff01; 你会学到什么 如何使用虚幻引擎及其元素 电子游戏力学原理 平衡计分卡几何原理 蓝图脚本的原则 如何设计、开发和编写你的关卡来复制你最喜欢的游戏 流派:电子学习| MP4 |视频:h264&…

atitit.userService 用户系统设计 v5 q330

atitit.userService 用户系统设计 v5 q330 1. 新特性1 2. Admin login1 3. 用户注册登录2 3.1. <!-- 会员注册使用 --> 商家注册2 3.2. <!-- 会员登录使用 -->3 3.3. <!-- 会员退出登录 -->3 3.4. <!-- 进入会员首页 -->3 3.5. <!-- 进入会员信…

python打包为exe文件_Pyinstaller(python打包为exe文件)

需求分析&#xff1a; python脚本如果在没有安装python的机器上不能运行&#xff0c;所以将脚本打包成exe文件&#xff0c;降低脚本对环境的依赖性&#xff0c;同时运行更加迅速。 当然打包的脚本似乎不是在所有的win平台下都能使用&#xff0c;win7有一部分不能使用&#xff0…

从风投看中国IT行业的发展

创业相关电视剧中经常会出现一个词“风投”&#xff0c;例如主角创业艰辛&#xff0c;得到了风投的帮助&#xff0c;从而走向了人生巅峰。而“风投”并不是一家企业&#xff0c;它是由无数风险投资公司一同组成的行业&#xff0c;今天就带大家了解一下风投与中国IT行业的紧密联…

c++ 字母排序

char a[123] {Z, s, p, l, j, r, q, v, n, m, C, F, D, B, A, 2, 0, Z, };for (int i 0; i < strlen(a); i){//字母排序for (int j i 1; j < strlen(a); j){if (a[j] < a[i]){char pTem a[j];a[j] a[i];a[i] pTem;}}}printf("%s\n", a); 版权声明&a…

李宏毅笔记机器学习(四)——Regression——Demo

视频来源&#xff1a; 李宏毅机器学习(2017)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili https://www.bilibili.com/video/av10590361/?p4 重点&#xff1a; &#xff08;1&#xff09;调节lr&#xff08;learning rate步长&#xff09;&#xff0c;lr参数的调节。迭代次数为1000次…

Blender 3.0机器人硬面建模材质渲染全流程学习课程

学习在Blender中建模硬表面机器人角色 你会学到什么 Blender 3.0建模工具 Blender 3.0硬面人物造型 机器人角色的UV展开 如何在Blender中渲染 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#xff0c;2 Ch 语言&#xff1a;英语中英文字幕&#xff08;…

python抓包工具_「docker实战篇」python的docker爬虫技术-fiddler抓包软件详细配置(七)...

挑选常用的功能给各位老铁介绍下。 fiddler第一次进入fiddlerfiddler会请求fiddler的官网&#xff0c;检查更新操作布局分布 工具栏File -capture traffic开启爬虫File -new Viewer新建立一个窗口File - save保存all session&#xff0c;request方式&#xff0c;reponse的方式z…

loadrunner支持https协议的操作方法-经验总结

问题&#xff1a;用户portal支持https协议&#xff0c;用loadrunner录制登陆脚本时发现未录制到用户名和密码 录制到的脚本如下&#xff1a; login() { lr_think_time(10); web_url("verifycode.jsp", "URLhttps://192.168.211.246:56661/portal/common/jsp/ver…

初试linux编译(ubuntu+vim)+玩转智能蛇

一.初试linux编译&#xff08;ubuntuvim&#xff09; 步骤&#xff1a; ①下载vmware15ubuntu桌面版映像 ②安装ubuntu ③下载vimgcc 在ubuntu终端输入&#xff1a; sudo apt-get install vim-gtk sudo apt-get install gcc④安装完毕后进行编译测试 1&#xff09;新建hellow…

shell学习之路:流程控制(if)

1.单分支if条件语句 1 if [ 条件判断式 ];then 2 程序 3 fi 4 或者 5 if [ 条件判断式 ] 6 then 7 程序 8 fi 注意事项: 1.if语句使用fi结尾&#xff0c;和一般语言使用大括号结尾不同 2.[ 条件判断式 ]就是使用test命令判断&#xff0c;所以中括号和条件判断式…

李宏毅机器学习笔记(五)-----Where does the error come from

视频来源&#xff1a; 李宏毅机器学习(2017)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili https://www.bilibili.com/video/av10590361/?p5 function set model error来源&#xff1a; &#xff08;1&#xff09;baise &#xff08;2&#xff09;variance问题一&#xff1a; 怎么…

Blender三维建筑场景动画制作学习教程

一起在Blender中创建一个三维低多边形场景动画 你会学到什么 这门课程是为那些喜欢在工作流程中成长的艺术家设计的 初学者 想学会让自己的资产活起来的艺术家。 希望扩展其技能集的游戏开发人员。 MP4 |视频:h264&#xff0c;1280720 |音频:AAC&#xff0c;44.1 KHz&#x…

springcloud 组件_SpringCloud组件mica 2.0.5发布,添加对sentinel、undertow指标收集

一、mica&#xff08;云母&#xff09;mica 由如梦技术内部的 lutool&#xff08;撸秃&#xff09; 演变而来。lutool 诞生于 2017 年&#xff0c;受 jhipster 启发逐步形成一个微服务的核心集。因 lutool 名称与功能不太符合&#xff0c;故在2019年开源时将其改名为 mica&…

access order by 判断是否除数为0

order by IIF(dz>0,yj/dz,0) desc转载于:https://www.cnblogs.com/slyzly/p/5379482.html