@

一. 暴力匹配

字符串匹配的最直接的方法就是暴力匹配,而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. CF158A Next Round 题解

    Content 有 \(n\) 个人参加比赛,第 \(i\) 名在第一轮的分数是 \(a_i\)(保证 \(a_i\geqslant a_{i+1}\))已知下一轮预计能进 \(k\) 人,当然如果有 ...

  2. std::function介绍 -转载

    类模版std::function是一种通用.多态的函数封装.std::function的实例可以对任何可以调用的目标实体进行存储.复制.和调用操作,这些目标实体包括普通函数.Lambda表达式.函数指 ...

  3. WPF控件界面自适应

    之前就听说WPF流式布局,顺滑的很.但由于专业只学习了winform,工作对界面的要求并不高一直没去玩它.目前公司一些软件都是WPF布局,加上工作内容涉及Socket通讯较多,决定用WPF做一个通讯小 ...

  4. React-Router(二)

    URL参数部分 import React from "react"; import { BrowserRouter as Router, Switch, Route, Link, ...

  5. SpringBoot整合Apache Shiro

    Subject 用户主体 (把操作交给SecurityManager)SecurityManager 安全管理器 (关联Realm)Realm   Shiro连接数据的桥梁 引入maven依赖 < ...

  6. RPA项目POC指南:概念、步骤与技巧

    "为什么部署RPA前要进行POC?RPA不是开箱即用吗?" 其实,RPA的实施并非总是一帆风顺,"碰坑"在所难免. 据安永报告显示,30%至50%的初始RPA项 ...

  7. Interesting Fibonacci(hdu 2814)

    Interesting Fibonacci Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Ot ...

  8. 破解C#反编译软件Reflector 11.1.0.2167(最新版)(附补丁下载)

    本文为原创作品,转载请注明出处,作者:Chris.xisaer E-mail:69920579@qq.com QQ群3244694 补丁下载地址:https://download.csdn.net/d ...

  9. Laravel 使用 maatwebsite/excel 时长数字出现科学计数法的解决办法

    在使用 maatwebsite/excel 包导出Excel的时候,有的单元格里会存放手机号等一大串的数字,这一串数字会被Excel软件处理为科学计数法,在后续处理数据的时候会产生不小的麻烦,一个个去 ...

  10. 山寨F407板子如何烧录正点原子例程、Keil下载提示Invalid ROM Table

    山寨F407板子如何烧录正点原子例程 手头这块块信赢达的STM32F407板子,是模仿正点原子探索者STM32F407板子的,外设和接口,几乎是一模一样. 探索者板子用的是STM32F407ZET6, ...