@

一. 暴力匹配

字符串匹配的最直接的方法就是暴力匹配,而KMP算法也是基于暴力算法进行改进。暴力匹配的思想如下:

  1. 对于文本串T和模式串P,从模式串P的第 0 号位置、文本串第 \(i_0\) 号位置开始逐一比对;
  2. 比对到中间某个时刻,若\(T[i ] == P[j]\),则比对继续进行,\(i++, j++\)
  3. 如果比对失败,则从模式串第0位和文本串的第\(i_0 + 1\)位继续进行

但是\(T[i_0 , i)\)和\(P[0, j)\)比对成功意味着\(T[i_0 , i)\)和\(P[0, j)\)完全相同的,掌握了\(P[0, j)\)那么也就意味着掌握了\(T[i_0 , i)\),下一轮的比对方案完全可以提前预知。

例1



在图中的比对过程中,主串中的 x 和模式串中的 y 失配,根据模式串中 y 以前的内容可以获知主串对应部分的内容。如果在下一步的比对过程中直接将主串中的 x 和模式串中的 e 进行比对,可以省去 6 次比对

二.KMP的基本思想

在对暴力破解的算法的分析中发现,对比在某个位置失败意味着在这之前的比对完全成功,主串中失配字符前的一段内容已经完全获知。利用这一点,对暴力算法可以进行两个方面的优化:

  1. 避免主串的回溯。暴力匹配当比对失败后,文本串的第\(i_0 + 1\)位、\(i_0 + 2\)位、……、\(i-1\)位的对比结果完全可以推导出来,没有必要再进行比对尝试;
  2. 模式串快速移动。基于和上面相同的原因,模式串的新的比对位置不需要从 0 开始。如例一中的模式串,字符y和字符e的前面都包含了"abc"这一部分,因此y前面的部分能和主串匹配成功,那么e前面的也一定能匹配成功。

因此对于模式串中的每个位置 j ,都能提前找到一个替代位置。

例2

模式串"abababca",对字符c而言,2号位的 a 和4号位的 a 都是能够在字符 c 发生失配时的一个可选择的位置

在诸多可选的继任位置中,位置下标越大,意味着已经成功匹配的长度越长,剩下需要比对的位置也就越少,因此 j 的继任位置\(next[j]\)定义为:

\[next[j] = \max(k | p_0 p_ 1...p_{k - 1} = p_{j - k}p_{j - k + 1}...p_{j - 1})
\]

通常定义\(next[0] = -1\)或者\(next[1] = 0\)(当字符串的下标从1开始时),这种规定是假想在模式串的起始位置的前一个有一个通配哨兵。

三.next[]的求法

1. 暴力求解

根据\(next[j]\)的定义,从逐一枚举字符P[j]的真前缀和真后缀,找出相等的真前缀和真后缀的长度,取长度的最大值即为\(next[j]\)

2. 递推求解

假设已经求得\(next[0, ... , j]\),递推求解\(next[j + 1]\)

\(next[j]\)已知意味着\(P[0, 1, ..., next[j] - 1]\)和\(P[j - next[j], ... , j - 1]\)是相等的,并且这个相等的部分是最大的,求取\(next[j + 1]\)时,只需要考察\(P[next[j]] == P[j]\)是否成立。如果成立,\(next[j + 1] = next[j] +1\) ,如果不成立,再考察\(P[next[next[j]]] == P[j]\)是否成立,依次类推,最终会收敛于\(next[0] + 1 = 0\)



插图来自视频

void buildNext(string str, int nt[]){
int len = str.size();
nt[0] = -1;
int t = nt[0], j = 0;
while(j < len - 1){
if(t < 0 || str[j] == str[t]){
nt[++j] = ++t;
}else{
t = nt[t];
}
}
}

四.KMP算法

在求解了next数组之后,kmp算法变得非常简单了。

int kmp(string str1, string str2){
int nt[str2.size()];
buildNext(str2, nt);//构建next表
int i = 0, j = 0;
while(i < str1.size() && j < str2.size()){//逐步比对
if(j < 0 || str1[i] == str2[j]){//比对成功时,前进一位,j < 0表示和通配符比对成功
i++; j++;
}else{//对比失败,找到新的位置比对
j = nt[j];
}
}
return i - j;
}

【算法】KMP的更多相关文章

  1. [每天默写一个算法]KMP

    [每天默写一个算法]KMP 作业要求:默写String的KMP算法. KMP是经典的字符串匹配算法.复杂度为O(n+m) public static class StringKMP { /// < ...

  2. 数据结构与算法--KMP算法查找子字符串

    数据结构与算法--KMP算法查找子字符串 部分内容和图片来自这三篇文章: 这篇文章.这篇文章.还有这篇他们写得非常棒.结合他们的解释和自己的理解,完成了本文. 上一节介绍了暴力法查找子字符串,同时也发 ...

  3. 经典算法 KMP算法详解

    内容: 1.问题引入 2.暴力求解方法 3.优化方法 4.KMP算法 1.问题引入 原始问题: 对于一个字符串 str (长度为N)和另一个字符串 match (长度为M),如果 match 是 st ...

  4. 笔记-算法-KMP算法

    笔记-算法-KMP算法 1.      KMP算法 KMP算法是一种改进的字符串匹配算法,KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的.具体实现就是实现一 ...

  5. 值得花费一周研究的算法 -- KMP算法(indexOf)

    KMP算法是由三个科学家(kmp分别是他们名字的首字母)创造出来的一种字符串匹配算法. 所解决的问题: 求文本字符串text内寻找第一次出现字符串s的下标,若未出现返回-1. 例如 text : &q ...

  6. 算法-KMP串匹配

    字符串匹配 http://www.cnblogs.com/jingmoxukong/p/4343770.html 模式匹配是数据结构中字符串的一种基本运算,给定一个子串,要求在某个字符串中找出与该子串 ...

  7. [C++] [算法] KMP算法

    KMP串匹配算法是一个经典的算法. 传统BF算法是传统的字符串匹配算法.很好理解.叶实现.但时间复杂度太高. 本文将从字符串模式字符串被称为.为了匹配字符串被称为主弦. KMP配时能够少移动从串的位置 ...

  8. [算法] kmp实现

    字符串查找是经典场景,也是面试中最常见的一道题. 说来惭愧,毕业3年了,才明白了kmp算法的实现,以前一直以为这类算法是基础,工作中中不会碰到[也的确没有碰到过...] 但是,对这些基本算法结构的理解 ...

  9. 程序员必会算法-KMP算法

    KMP算法是一种优秀的字符串匹配算法,字符串匹配的常规算法是一步一步进行移位和比较操作,直至找到完全相匹配的字符串. 下面通过一个例子,为大家仔细说明KMP算法的使用和思路: 问题: 在字符串“DEA ...

  10. 算法 kmp算法

    kmp算法是改进后的字符匹配算法,它与bf算法的区别是,每次从串与主串匹配失败后,从串与主串匹配的位置不同. 下面具体说下这两种算法的区别: 主串:BABCDABABCDABCED 从串:ABCDAB ...

随机推荐

  1. Uni-app原生插件入门使用教程-[1]从Uni-app插件市场试用插件

    [1]从Uniapp插件市场试用插件 当HBuilderX中提供的能力无法满足App功能需求,需要通过使用Andorid/iOS原生开发实现时,可使用App离线SDK开发原生插件来扩展原生能力. 如使 ...

  2. SpringBoot整合openoffice实现word文档的读取和导入及报错处理

    先安装openoffice4 Linux系统安装参考:https://www.cnblogs.com/pxblog/p/11622969.html Windows系统安装参考:https://www. ...

  3. Visual Studio Code常用快捷键

    说明 以下快捷键适用于windows环境下, Mac请将ctrl替换为command按键: 部分快捷键或不一样. 查看VSCode快捷键定义: settings -> keymaps. 目前使用 ...

  4. C++常用工具库(C语言文件读写,日志库,格式化字符串, 获取可执行文件所在绝对路径等)

    前言 自己常用的工具库, C++ 和C语言实现 使用cmake维护的项目 持续更新..... 提供使用范例, 详见example文件夹 windows使用的VS通过了的编译. Linux(Ubuntu ...

  5. JSON(JS 对象简谱,一种数据交换格式)

    JSON(JavaScript Object Notation, JS 对象简谱) 是一种轻量级的数据交换格式 存储和表示数据的文本格式 层次结构清晰.简洁 JSON是一个序列化的对象或数组 1.js ...

  6. 【优雅代码】01-lombok精选注解及原理

    [优雅代码]01-lombok精选注解及原理 欢迎关注b站账号/公众号[六边形战士夏宁],一个要把各项指标拉满的男人.该文章已在github目录收录. 屏幕前的大帅比和大漂亮如果有帮助到你的话请顺手点 ...

  7. 如何通过Navicat远程访问宝塔面板安装的MySQL数据库

    运行环境描述 阿里云ECS 系统:CentOS Linux 7.4.1708 (Core)宝塔面板: 6.9.0数据库:MySQL 5.7.19 Navicat 远程连接 Navicat报错信息: 错 ...

  8. jboss CVE-2015-7501 反序列化漏洞复现

    JBOSS反序列化漏洞 环境: vulfocus jboss CVE-2015-7501 云服务器 kali攻击机 基本原理:JBoss在/invoker/JMXInvokerServlet请求中读取 ...

  9. PostgreSQL相关知识概念

    本文主要介绍PostgreSQL数据库的一些重要知识点, 包括数据库.模式.表空间.用户/角色等概念和关系, 帮助用户理解PostgreSQL数据库的重要概念, 从而能够更好的使用PostgreSQL ...

  10. Jedis 基本使用

    引入 jedis 依赖: <!-- https://mvnrepository.com/artifact/redis.clients/jedis --> <!-- Dec 15, 2 ...