KMP算法理解(参考BILIBILI正月点灯笼)
前言
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++;}}
}
- 第一个判断为判断当前pattern是否匹配结束
- 第二个判断若相等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正月点灯笼)相关推荐
- leetcode28. Implement strStr() (以及个人对KMP算法理解)
kmp算法标准板子题 class Solution { public:vector<int> getNext(string needle){vector<int> next(n ...
- KMP算法理解(转)
(作者matrix67) KMP算法是拿来处理字符串匹配的.换句话说,给你两个字符串,你需要回答,B串是否是A串的子串(A串是否包含B串).比如,字符串A="I'm matrix67&quo ...
- KMP算法理解(超简洁-易懂代码)
文章目录 KMP算法 1. 暴力做法是怎么做的 1.1 时间复杂度: O(n^2) 2. 怎么去优化它 2.1 一般情况: 2.2 原理: 2.3 匹配过程 2.4 kmp 匹配的实现代码 2.5 n ...
- 【数据结构】详解KMP算法
字符串匹配算法:简单来说就是给你一个主串和一个子串,让你查找子串在主串中的位置,找到返回下标. 常见的两种算法:BF算法.KMP算法 这两种算法是怎样的思路呢,我们接着往下看: 目录 BF算法(暴力算 ...
- 459. 重复的子字符串-KMP算法
459. 重复的子字符串 给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成. 示例 1: 输入: s = "abab" 输出: true 解释: 可由子串 & ...
- 数据结构与算法之美笔记——基础篇(下):图、字符串匹配算法(BF 算法和 RK 算法、BM 算法和 KMP 算法 、Trie 树和 AC 自动机)
图 如何存储微博.微信等社交网络中的好友关系?图.实际上,涉及图的算法有很多,也非常复杂,比如图的搜索.最短路径.最小生成树.二分图等等.我们今天聚焦在图存储这一方面,后面会分好几节来依次讲解图相关的 ...
- 深化对KMP算法的理解
KMP算法 看到这么一句话:你的名字是我告白语中的子串 文章目录 KMP算法 参考代码 预处理模式串的理解 入门题目 KMP一开始理解起来是比较困难的,下方是结合自己的理解写出来代码,仅作参考, (网 ...
- 七分钟理解什么是 KMP 算法
本文是介绍 什么是 BF算法.KMP算法.BM算法 三部曲之一. KMP算法 内部涉及到的数学原理与知识太多,本文只会对 KMP算法 的运行过程. 部分匹配表 .next数组 进行介绍,如果理解了这三 ...
- 【数据结构】字符串 模式匹配算法的理解与实现 Brute Force算法(BF算法)与KMP算法 (C与C++分别实现)
#笔记整理 若不了解串的定义,可至: 串(string)的定义与表示 查看 串的模式匹配算法 求子串位置的定位函数 Index(S, P, pos) 求子串的定位操作通常称作串的模式匹配(其中子串P称 ...
最新文章
- 分布式系统关注点:无状态
- unity开宝箱动画_unity简单动画实现
- JavaScript实现combine With Repetitions结合重复算法(附完整源码)
- 画图设置刻度_总结了16个常用的matlibplot画图技巧(附源码)
- Reasoning about Entailment with Neural Attention-学习笔记
- IP地址的简单说明---Linux学习笔记
- 3D Mapping with an RGB-D Camera(RGBD SLAM V2 )论文笔记
- leetcode115 不同的子序列
- 准备写个Spring Boot教程
- ieda中快捷搜索_快捷指令(07)早上好(三)播报当日日程安排。
- 2.软件架构设计:大型网站技术架构与业务架构融合之道 --- 架构的道与术
- matlab 找到数组中第一个不连续点_MATLAB新手入门篇1(基础)
- 电缆桥架安装要求及规范指导
- 局域网ip冲突检测工具_只需一台Android设备就能打通局域网内部通讯:文字聊天与文件传输...
- 电脑如何打开虚拟化设置?
- 证券行业智慧化转型思考
- 计算机专业大学期间有必要参加很多竞赛吗?
- 常州和南京计算机工资水平,南京和苏州哪一个城市工资高?六张图带你看懂江苏各市平均工资情况...
- 河南省 第十一届 ACM 省赛 试题
- 再次聚焦收入分配制度改革
热门文章
- linux if 判断文件,shell中的逻辑判断,if 判断文件、目录属性,if判断的一些特殊用法...
- nsga 的java实现_Java – Scala遗传算法(GA)库中的模拟二进制交叉(SBX)交叉运算符
- 在线电子书阅读小程序,微信小程序电子书阅读,微信小程序小说阅读器毕业设计作品
- armbian开启ssh_Armbian Ubuntu启用netplan配置网络
- android朋友圈发文字换行,微信朋友圈全文展开 朋友圈文字怎么换行朋友圈发多行文字...
- 视频文件损坏无法播放怎么修复?
- cad一键卸载工具叫什么_「CAD」一键卸载AutoCAD工具、拿走不谢
- 朱清时——物理学步入禅境:缘起性空-(技术工作者上升到哲学思维)
- 以前给客户开发了一个本地同城小程序
- python访问局域网共享文件夹