BF算法

本章重点是是KMP算法,但是由于其较难理解,先从更简单朴素的BF算法开始。

其思路非常简单

也就是,对这样两个字符串(称短的为模式串,长的为主串):

让主串和模式串的每个字符逐个匹配,如果从这个位置开始匹配不成功,则从主串的下一个字符开始匹配,直到遍历完主串。可以得到这份代码

int BF(string a, string b) {int la = a.length(), lb = b.length();int j = 0, i = 0;//注意从0 开始//j为主串a的下标,i为模式串b的下标while(j<la&&i<lb){if (a[j] == b[i]){//逐个匹配j++;i++;}else {j = j - i + 1;i = 0;}}if (i == lb)return j - i;//返回下标return 0;
}

因为对每个主串的字符都要遍历一遍模板串,所以很容易得出其时间复杂度为O(n*m)

其中n和m分别为两个串的串长。也就是O(n^2)的复杂度,还是比较低效的。但容易理解。

其中需要注意点就是,如果从主串的一个起点字符位置j开始不与模板串匹配,则要减去位移量回溯,并加1使主串匹配起点移动到下一位置。

KMP算法

从BF算法入手,我们在遍历主串的同时匹配完还要将已经移动的主串指针回溯到原来的位置的下一个位置,模式串也相应的回退。这也是BF算法低效率的原因。而KMP算法则解决了这一个问题。

试想,对于这样一个的两个串当匹配到j和i的情况时(红框)匹配失败,如果是BF算法,我们要将主串和模式串的指针都要回退。这样效率就非常低了。但是如果我们可以得到一个位置pos使模式串的指针 i退回到这个pos时不移动主串指针,继续匹配。也能完成任务。那么这个算法的效率就非常高了(因为只需要遍历一次主串)。

我们先假设每次错配的时候我们都可以得到这个pos使模式串的指针 i退回到这个pos时不移动主串指针 j,也能正确的完成程序。而且很容易知道这个pos的所有值和模式串的每个字符位置相关,那么我们可以得到一个数组next[],其索引为模式串每个元素的下标。

那么我们可以得到以下的代码(相比BF算法只改动了主串和模式串指针回溯的操作)

int KMP(string a, string b) {int la = a.length(), lb = b.length();int j = 0, i = 0;//注意从0 开始//j为主串a的下标,i为模板串b的下标while(j<la&&i<lb){if (a[j] == b[i]){//逐个匹配j++;i++;}else {i = next[i];}}if (i == lb)return j - i;//返回下标return 0;
}

接下来的重点也是难点,就是求出next[]数组得到,每次错配时我们应该让模式串指针回退到什么位置。

根据KMP算法,我们会知道当模式串指针回退到当前模式串的子串已经匹配成功的部分)的最大公共前缀后缀处(举个例子比如a b c g a b的最大公共前后缀处就是c也就是第三个位置,满足条件的前缀后一个位置)。这个位置可以保证主串当前指针之前不会出现可匹配出模式串的主串位置。也就不需要回溯再判断了。

这种回退的说法过于抽象,下面以图像来说明

例:

我们有这样的主串和模式串,其中主串的指针为 i,模式串指针为 j:

我们各从第一个字符开始匹配,直到错配(蓝框),此时i=2:

由图可知,当j=i=5时(指针起点为0)发生错配。但错配点之前,模式串和主串完全相同。

如果是朴素的算法,我们会各种回退,从起点的下一个主串元素开始逐个匹配。但是KMP算法告诉我们,我们只需要把模式串的指针回退到错配点之前的最大前后缀处(白色箭头所指)也就是next[i]=2也就是把模式串的前缀移动到原后缀的位置,即 i = next[i];

从上图的指针位置开始继续匹配就能跳过中间多余的计算。

主程序和思路已经介绍完毕,接下来是next[]数组的实现,也就是

找到每一个模式串子串的最大前后缀点

这一步其实与KMP的主程序是独立的,不管KMP怎么实现,都要先预处理得到next[]数组,所以可以单独分析

对这样一个模式串的子串(和主串匹配成功的部分),其中模式串当前的下标 i = 9,next数组作用就是找到前 i-1个元素里的最长前后缀点,使 模式串下标跳转到对应位置

我们此时要计算next[9]。我们可以从两种途径得到:

1.如果T[8]和只有前7个元素的字符串的最长公共前后缀的最后一个前缀元素相同,那么我们只要在原来的解上加一即可,设最长公共前后缀的长度为k,即next[9]=next[8]+1=k+1

2.如果T[8]和只有前7个元素的子串的最长公共前后缀的最后一个前缀元素不同,那么我们从前七个元素的子串的最长公共前后缀的前缀中以相同方法找出更短的子串。

一般化的公式

其中的最长公共前后缀的 最长 保证了中间不会出现可能包含子串的主串位置

如果理解了上面的过程,则可以得到:

int next[100];
void pos(string t,int nx[]) {int j = 0, k = -1;next[0] = -1;//与正常值区分while (j < t.length()-1) {//注意边界if (k == -1 || t[j] == t[k]) {j++; k++;next[j] = k;}else k = next[k];}}

其中 模式串自配时错配的情况。设k指针为模式串自配时的前缀指针,j为模式串自配时的后缀指针。

比如:

1.如果k指针对应的字符与j指针对应的字符不同则k保留为第一个元素也就是k=0的位置。j向后移动。

2.如果相同,k和j一起移动,直到遍历完模式串或直到k和j对应字符不匹配。

3.到了图中这种情况,也就是自配失败的情况则要将k指针回溯到更小的前缀子串。

将前后缀移动,对应更直观。 因为错配,k指针要发生回溯,而回溯的位置就是k之前的子串的最长前后缀处next[3],因为我们此时正在求next[9],next[3]是已经求过的,所以我们可以直接访问这个位置,如果访问到这个位置,前后缀依然不匹配则不移动后缀j而不断回溯k。直到匹配成功或者到第一个元素(next[0]=-1)时,如果一直没有匹配成功,也就是说此时最长前后缀长度为0,则k的值赋为next[0],也就是-1.并回到第一个if分支处的k==-1的情况

如果是这种情况。此时next[9]的值将是k++,也就是-1+1=0。


虽然知道了我只要这样做,代码就能完成任务。但一直不理解为什么我要找最长公共 前后缀,这个想法是怎么想出来的。这几天也一直在思考,现在有了一些进展。

如这个例子

i和j 的字符不匹配,但之前从A为起点那个绿色框的是已经匹配成功的,也就是匹配成功的部分上下两个串是完全相同的。

很明显,我们可以先得到一个事实——C字符处为当前子串的最长公共前后缀处,最长公共前后缀是AB那么我们假设,C之前存在以其为起点匹配可以得到模式串的位置。比如B处。因为我们假设这种情况是匹配成功的,也就是说B为起点存在跟模式串一模一样的串ABCAB,原串相同,对应子串也相同。也就是从B开始到 i处的子串BCAB(设其长度为L)和模式串从第一个字符开始L长的子串ABCA是相同的。但是很显然主串的子串BCAB是匹配成功相同串ABCAB的后缀模式串的子串BCAB是匹配成功串的前缀,如果这个假设成立,那么最长公共前后缀应该为BCAB才对,与匹配成功串的最长公共前后缀是AB的事实矛盾。

因为如此也就说明匹配成功串的最长公共前后缀处之前不会存在以其为起点匹配可以得到模式串的位置。

所以我们在回溯的时候可以直接跳过该部分直接让当前模式串前缀和当前主串后缀匹配,省去而外的匹配操作。

字符串匹配—BF算法和KMP算法相关推荐

  1. Algorithm:C++语言实现之字符串相关算法(字符串的循环左移、字符串的全排列、带有同个字符的全排列、串匹配问题的BF算法和KMP算法)

    Algorithm:C++语言实现之字符串相关算法(字符串的循环左移.字符串的全排列.带有同个字符的全排列.串匹配问题的BF算法和KMP算法) 目录 一.字符串的算法 1.字符串的循环左移 2.字符串 ...

  2. BF算法和KMP算法

    给定两个字符串S和T,在主串S中查找子串T的过程称为串匹配(string matching,也称模式匹配),T称为模式.这里将介绍处理串匹配问题的两种算法,BF算法和KMP算法. BF算法 (暴力匹配 ...

  3. 若S作主串,P作模式串,试分别写出利用BF算法和KMP算法的匹配过程。

    目   录 题目: 百度文库-答案: (1) (2) MOOC标准答案: (1) (2) mooc答案-截图: 数据结构(C语言版)-严蔚敏2007 题目: 设字符串S='aabaabaabaac', ...

  4. 模式串匹配的BF算法和KMP算法

    KMP是三位大牛:D.E.Knuth.J.H.Morris和V.R.Pratt同时发现的.为了解决模式匹配问题,也即寻找模式串(子串)在主串中第一次出现的位置,若模式串在主串中不存在则返回-1. 简单 ...

  5. 【算法篇-字符串匹配算法】BF算法和KMP算法

    目录 前言 1. BF算法 1.1 画图分析 1.3 BF 算法的时间复杂度 2. KMP 算法 2.1 KMP 算法和 BF 算法 的区别 2.1.1 为什么主串不回退? 2. 2 next 数组 ...

  6. 数据结构之字符串匹配算法(BF算法和KMP算法)

    字符串匹配算法: 就是给定两个串,主串(s)和子串(sub), 查找子串是否在主串里面,如果找到便返回子串在主串中第一个元素的位置下标,否贼返回-1,. 在这里我 们讨论的时候主要用字符串来举例实现. ...

  7. 串的BF算法和KMP算法个人总结

    子串(模式串)的定位操作通常称作串的模式匹配 其中包含最初始的BF算法(Brute-Force)即简单匹配算法或者称作朴素的模式匹配算法,利用穷举法的思路 另一种就是改进后的KMP算法,还有对KMP算 ...

  8. 字符串匹配BF/RK/BM/KMP算法

    主串长度m,匹配串(模式串)长度n. 一.BF 强制算法比较,最容易想到的,时间复杂度O(m*n) 二.RK 计算出匹配串的哈希值,遍历主串,求每次对应位置相同长度的子串哈希值,比较两者是否相同. 若 ...

  9. BF算法和KMP算法实现

    https://blog.csdn.net/xxibgdrgn_liqian_a_/article/details/80690593

最新文章

  1. python设计选择题代码_《Python程序设计》试题库
  2. oc35--自定义构造方法
  3. 白血病孕妇产子继母子双双安然
  4. DIY一个基于树莓派和Python的无人机视觉跟踪系统
  5. UE4学习-自定义相机视图
  6. python三维数据转换成二维_5大Python可视化库到底选哪个好?一篇文章搞定从选库到教学...
  7. 新垣结衣自拍照_如何阻止自拍照出现在iPhone的自拍照专辑中
  8. BeetleX.Http.Clients访问https服务
  9. ora-32004 oracle10,ORA-32004错误的解决方法
  10. Linux 安装jdk8
  11. Power Query M语言全部list函数,快速分类掌握
  12. java 调用关机命令_java调用关机命令
  13. 小明左、右手中分别拿两张纸牌:黑桃10和红桃8.现在交换手中的牌。
  14. matlab贝塔分布,怎么拟合贝塔分布函数
  15. java实验3_Java实验3
  16. Mybatis核心配置文件
  17. 《趣学Python编程》——第1部分 学习编程 第1章 Python不是大蟒蛇 1.1 关于计算机语言...
  18. 【无标题】程序员如何优雅地摸鱼?
  19. python数据结构基础(单链表,多链表,二叉树)
  20. uoni扫地机器人好用吗_扫地机器人好用吗?扫盲选购看这篇

热门文章

  1. sql server 2019数据库安装包 免费下载
  2. 计算机操作系统在线作业,电子科技大20春《计算机操作系统》在线作业2
  3. tslib Linux命令测试,tslib 的编译和触摸屏的测试
  4. ubuntu18输入法繁体输出转简体
  5. Flutter学习记录——23.实现一个类似淘宝的商品展示页面
  6. 【mind+】机器人对话互动游戏编程
  7. windows 找不到文件 ‘C:\ApplicationC\UltraEdit24_18212\UltraEdit24.20.0.40(x64)\UltraEdit\uedit32.exe’
  8. xbox360游戏下载_完成的乐趣-通过Xbox向后兼容性探索旧游戏
  9. python.exe-找不到序数:无法定位序数242与动态链接库libiomp5md.dll上。
  10. 二、IDEA设置、快捷键和代码模板