前言

KMP算法最近看了很多的博客和视频始终没有清楚理解NEXT数组的构建,在B站看到正月点灯笼大神的视频,里面提出的前缀表对我有很大启发,今天来记录分享一下。
BILIBILI 正月点灯笼

定义

string text;//目标字符串
string pattern; //匹配字符串
int i,j;//为两个字符串索引 text[i],pattern[j]
int n,m;//分别为两个字符串长度

算法

KMP框架

在灯神的视频里引入了一个前缀表(Prefix table)的概念来替代Next数组,我觉得更容易理解,在这里前缀的意思我就不赘述了,可以自行百度。
假设待匹配的字符串Pattern=“ABABAAC”。

   0  A0  AB1  ABA2  ABAB3  ABABA1  ABABAA0  ABABAAC

于是我们可以根据每一个字母的前缀数建立一个前缀表,为了方便后面KMP搜索,将其向后移一位,第一位定义为-1,于是有了这样的一个数组

int prefix[] = {-1,0,0,1,2,3,1};

对应到数组为这样的形式

当我们遍历text字符串时,若发现第j位Pattern不匹配时候我们这样处理(KMP匹配就不赘述了)

如图,我们在pattern字符串第2位发现A和B不匹配,我们这时候查找前缀表数组,发现第2位对应着是0,这时则将pattern第0位移动到这里j = prefix[j] = 0,如图。


如此往复,每次发现不匹配则将前缀表对应数字的下标的位置向后移动,如果移动到prefix[0]=-1,则将整个pattern向后移动一位(与第-1位移动到第0位一个意思)

按这样的模式匹配,当我们pattern遍历完成就可以确定一个匹配的数据,此时若我们还要继续往下匹配,我们将pattern移动到当前前缀表的数字处,即 j = prefix[j]。于是我们就可以写出kmp匹配的代码

void kmp_search(string text, string pattern) {int n = pattern.length(), m = text.length();int i = 0, j = 0;//prefix_table(pattern);//move_prefix_table(n);while (i < m) {if (j == n - 1 && text[i] == pattern[j]) {cout << "Find pattern at" << i - j << endl;j = prefix[j];}if (text[i] == pattern[j]) i++, j++;else {j = prefix[j];if (j == -1) i++, j++;}}
}
  1. 第一个判断为判断当前pattern是否匹配结束
  2. 第二个判断若相等i和j向后移动一位,若不相等如上述按前缀表移动,前缀表数值为-1时移动一位。

前缀表构建

至此,我们已经了解了怎么通过前缀表匹配,现在要来构造前缀表。若是通过暴力枚举,仍然要花费很大的时间复杂度构建前缀表,于是需要通过之前的数据和规律来构造

   0  A0  AB1  ABA2  ABAB3  ABABA1  ABABAA0  ABABAAC

这里我们用整型变量len来表示当前最大前缀长度(这里指的是真前缀,长度小于字符串),用整型变量i来表示当前匹配的位置,如图第一位永远为0,于是len = 0。对于接下来的每一个字符串我们只需要判断新增加的字符pattern[i]是否与pattern[len]相等,若相等则len++;这里仍然存在一个问题,如下图。

当我们插入第7位‘A’时,此时len=2,i=6,我们发现 pattern[len] != pattern[i],但是插入的‘A’与字符串开头相同,所以这种情况下len不能简单等于0,应该进行如下操作(灯神视频里讲的有些乱可以自己看视频理解下)。

void prefix_table(string pattern) {prefix[0] = 0;int len = 0;int i = 1;while (i < pattern.length()) {if (pattern[i] == pattern[len]) {len++;prefix[i] = len;i++;}else {if (len > 0) len = prefix[len - 1];else prefix[i++] = len;}}
}

这样我们就完成了前缀表的构建,但记得之前还提到过需要将前缀表向前移动一位利于KMP搜索,于是还需如下函数(在函数中无法动态获取数组大小,于是当做参数传入)。

void move_prefix_table(int n) {int i;for (int i = n; i > 0; i--) prefix[i] = prefix[i - 1];prefix[0] = -1;
}

于是整合全部功能就完成了KMP搜索。

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
int prefix[N];void prefix_table(string pattern) {prefix[0] = 0;int len = 0;int i = 1;while (i < pattern.length()) {if (pattern[i] == pattern[len]) {len++;prefix[i] = len;i++;}else {if (len > 0) len = prefix[len - 1];else prefix[i++] = len;}}
}
//向前移一位,prefix[0] = -1
void move_prefix_table(int n) {int i;for (int i = n; i > 0; i--) prefix[i] = prefix[i - 1];prefix[0] = -1;
}void kmp_search(string text, string pattern) {int n = pattern.length(), m = text.length();int i = 0, j = 0;prefix_table(pattern);move_prefix_table(n);while (i < m) {if (j == n - 1 && text[i] == pattern[j]) {cout << "Find pattern at" << i - j << endl;j = prefix[j];}if (text[i] == pattern[j]) i++, j++;else {j = prefix[j];if (j == -1) i++, j++;}}
}int main() {cin.tie(0);ios::sync_with_stdio(false);string text,pattern;cin >> text >>pattern;kmp_search(text,pattern);return 0;
}

KMP算法理解(参考BILIBILI正月点灯笼)相关推荐

  1. leetcode28. Implement strStr() (以及个人对KMP算法理解)

    kmp算法标准板子题 class Solution { public:vector<int> getNext(string needle){vector<int> next(n ...

  2. KMP算法理解(转)

    (作者matrix67) KMP算法是拿来处理字符串匹配的.换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串).比如,字符串A="I'm matrix67&quo ...

  3. KMP算法理解(超简洁-易懂代码)

    文章目录 KMP算法 1. 暴力做法是怎么做的 1.1 时间复杂度: O(n^2) 2. 怎么去优化它 2.1 一般情况: 2.2 原理: 2.3 匹配过程 2.4 kmp 匹配的实现代码 2.5 n ...

  4. 【数据结构】详解KMP算法

    字符串匹配算法:简单来说就是给你一个主串和一个子串,让你查找子串在主串中的位置,找到返回下标. 常见的两种算法:BF算法.KMP算法 这两种算法是怎样的思路呢,我们接着往下看: 目录 BF算法(暴力算 ...

  5. 459. 重复的子字符串-KMP算法

    459. 重复的子字符串 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成. 示例 1: 输入: s = "abab" 输出: true 解释: 可由子串 & ...

  6. 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)

    图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...

  7. 深化对KMP算法的理解

    KMP算法 看到这么一句话:你的名字是我告白语中的子串 文章目录 KMP算法 参考代码 预处理模式串的理解 入门题目 KMP一开始理解起来是比较困难的,下方是结合自己的理解写出来代码,仅作参考, (网 ...

  8. 七分钟理解什么是 KMP 算法

    本文是介绍 什么是 BF算法.KMP算法.BM算法 三部曲之一. KMP算法 内部涉及到的数学原理与知识太多,本文只会对 KMP算法 的运行过程. 部分匹配表 .next数组 进行介绍,如果理解了这三 ...

  9. 【数据结构】字符串 模式匹配算法的理解与实现 Brute Force算法(BF算法)与KMP算法 (C与C++分别实现)

    #笔记整理 若不了解串的定义,可至: 串(string)的定义与表示 查看 串的模式匹配算法 求子串位置的定位函数 Index(S, P, pos) 求子串的定位操作通常称作串的模式匹配(其中子串P称 ...

最新文章

  1. 分布式系统关注点:无状态
  2. unity开宝箱动画_unity简单动画实现
  3. JavaScript实现combine With Repetitions结合重复算法(附完整源码)
  4. 画图设置刻度_总结了16个常用的matlibplot画图技巧(附源码)
  5. Reasoning about Entailment with Neural Attention-学习笔记
  6. IP地址的简单说明---Linux学习笔记
  7. 3D Mapping with an RGB-D Camera(RGBD SLAM V2 )论文笔记
  8. leetcode115 不同的子序列
  9. 准备写个Spring Boot教程
  10. ieda中快捷搜索_快捷指令(07)早上好(三)播报当日日程安排。
  11. 2.软件架构设计:大型网站技术架构与业务架构融合之道 --- 架构的道与术
  12. matlab 找到数组中第一个不连续点_MATLAB新手入门篇1(基础)
  13. 电缆桥架安装要求及规范指导
  14. 局域网ip冲突检测工具_只需一台Android设备就能打通局域网内部通讯:文字聊天与文件传输...
  15. 电脑如何打开虚拟化设置?
  16. 证券行业智慧化转型思考
  17. 计算机专业大学期间有必要参加很多竞赛吗?
  18. 常州和南京计算机工资水平,南京和苏州哪一个城市工资高?六张图带你看懂江苏各市平均工资情况...
  19. 河南省 第十一届 ACM 省赛 试题
  20. 再次聚焦收入分配制度改革

热门文章

  1. linux if 判断文件,shell中的逻辑判断,if 判断文件、目录属性,if判断的一些特殊用法...
  2. nsga 的java实现_Java – Scala遗传算法(GA)库中的模拟二进制交叉(SBX)交叉运算符
  3. 在线电子书阅读小程序,微信小程序电子书阅读,微信小程序小说阅读器毕业设计作品
  4. armbian开启ssh_Armbian Ubuntu启用netplan配置网络
  5. android朋友圈发文字换行,微信朋友圈全文展开 朋友圈文字怎么换行朋友圈发多行文字...
  6. 视频文件损坏无法播放怎么修复?
  7. cad一键卸载工具叫什么_「CAD」一键卸载AutoCAD工具、拿走不谢
  8. 朱清时——物理学步入禅境:缘起性空-(技术工作者上升到哲学思维)
  9. 以前给客户开发了一个本地同城小程序
  10. python访问局域网共享文件夹