算法学习笔记【6】| KMP 算法
KMP(Knuth-Morris-Pratt字符串查找算法)
KMP 算法是可以快速在文本串 s 中找到模式串 a 的算法。
Part 1:幼稚的算法
首先思考我们在暴力匹配模式串时的思路:

一旦有一位失配,就需要整个回溯,导致时间复杂度超标。
而 KMP 算法主要就是优化了这个回溯的问题。
一个人有多强不在于他能在顺境时走得多远,而在于他在逆境时能多久找回曾经的自己。
KMP 算法
首先我们要考虑让某个点不回溯,再优化另一个点的回溯过程。
KMP 给出了这样的一种方式:
设 i 表示文本串的位置,j 表示模式串的位置,我们让 i 不动,j 回溯到最合适的位置,这个位置,我们记为PMT(Partial Match Table,部分匹配表)。
PMT 数组的含义,也可以这样表示:
1 到 j 子串的最长公共前后缀长度。
就像这样:
当然,最长前后缀是可以重叠的:
那就有个问题,难道最长的不是整个串吗?所以为了避免卡 bug,PMT 要求这个公共前后缀的长度要小于子串长度。
我们在考虑一开始那个发生失配的情况,用 KMP 算法就可以变成这样:
实际上我们没有移动 i,只是让 j 变成了 pmt[j-1]。
如果这一位继续失配,那么 j 又变成了 pmt[j-1]。
反复如此,直到不得不移动 i 为止。
那么代码可以写成这样:
for(int i=0,j=0;i<s.size();i++){
while(j && s[i] != a[j])
j = pmt[j-1];
if(s[i] == a[j]) j++;
if(j == a.size())
j = pmt[j-1];
}
对于每一位首先处理失配的情况,然后判断是否能匹配当前位置,特别的是当 j 匹配完后(匹配成功),就需要准备下一次匹配,也可以理解为 j 的下一位(空)和 i 的下一位失配了。
不过我们上面的代码是假设 pmt 数组已经求出,别忘了求出 pmt 本身也不简单。
一个精妙的方法是进行模式串的自匹配。首先将模式串错开一位,然后和自己匹配一次,这样每次匹配的最大长度就刚好是公共前后缀的长度!
代码如下:
#include <bits/stdc++.h>
using namespace std;
int main(){
string a;
cin>>a;
int pmt[114]={0};
for(int i=1,j=0;i<a.size();i++){
while(j && a[i] != a[j])
j = pmt[j-1];
if(a[i] == a[j]) j++;
pmt[i] = j;
}
for(int i=0;i<a.size();i++){
cout<<pmt[i]<<' ';
}
return 0;
}
例题和代码
border 其实就是 pmt 数组。
const int N=1000005;
int pmt[N];
int main(){
ios_base::sync_with_stdio(false);cin.tie(0);cout.tie(0);
string s,a;
cin>>s>>a;
for(int i=1,j=0;i<a.size();i++){
while(j && a[i] != a[j])
j = pmt[j-1];
if(a[i] == a[j]) j++;
pmt[i] = j;
}
for(int i=0,j=0;i<s.size();i++){
while(j && s[i] != a[j])
j = pmt[j-1];
if(s[i] == a[j]) j++;
if(j == a.size()){
cout<<i+1-(a.size()-1)<<endl;
j = pmt[j-1];
}
}
for(int i=0;i<a.size();i++){
cout<<pmt[i]<<' ';
}
return 0;
}
算法学习笔记【6】| KMP 算法的更多相关文章
- 【算法学习笔记】Meissel-Lehmer 算法 (亚线性时间找出素数个数)
「Meissel-Lehmer 算法」是一种能在亚线性时间复杂度内求出 \(1\sim n\) 内质数个数的一种算法. 在看素数相关论文时发现了这个算法,论文链接:Here. 算法的细节来自 OI w ...
- 算法学习笔记:Kosaraju算法
Kosaraju算法一看这个名字很奇怪就可以猜到它也是一个根据人名起的算法,它的发明人是S. Rao Kosaraju,这是一个在图论当中非常著名的算法,可以用来拆分有向图当中的强连通分量. 背景知识 ...
- 算法学习笔记:Tarjan算法
在上一篇文章当中我们分享了强连通分量分解的一个经典算法Kosaraju算法,它的核心原理是通过将图翻转,以及两次递归来实现.今天介绍的算法名叫Tarjan,同样是一个很奇怪的名字,奇怪就对了,这也是以 ...
- Miller-Rabin 与 Pollard-Rho 算法学习笔记
前言 Miller-Rabin 算法用于判断一个数 \(p\) 是否是质数,若选定 \(w\) 个数进行判断,那么正确率约是 \(1-\frac{1}{4^w}\) ,时间复杂度为 \(O(\log ...
- 算法笔记之KMP算法
本文是<算法笔记>KMP算法章节的阅读笔记,文中主要内容来源于<算法笔记>.本文主要介绍了next数组.KMP算法及其应用以及对KMP算法的优化. KMP算法主要用于解决字符串 ...
- 算法学习笔记(20): AC自动机
AC自动机 前置知识: 字典树:可以参考我的另一篇文章 算法学习笔记(15): Trie(字典树) KMP:可以参考 KMP - Ricky2007,但是不理解KMP算法并不会对这个算法的理解产生影响 ...
- C / C++算法学习笔记(8)-SHELL排序
原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...
- GMM高斯混合模型学习笔记(EM算法求解)
提出混合模型主要是为了能更好地近似一些较复杂的样本分布,通过不断添加component个数,能够随意地逼近不论什么连续的概率分布.所以我们觉得不论什么样本分布都能够用混合模型来建模.由于高斯函数具有一 ...
- Manacher算法学习笔记 | LeetCode#5
Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...
- Johnson算法学习笔记
\(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...
随机推荐
- 阿里数据库SRE(转)
SRE的职责划分却不尽相同,那么SRE究竟在做什么? SRE的职责 SRE主要负责Google所有核心业务系统的可用性.性能.容量相关的事情,根据<Site Reliability Engine ...
- Java并发编程实例--14.在一个同步类中安排独立属性
当你使用synchronized关键字去保护一个代码块时,你必须传入一个对象的引用. 正常来讲,你讲使用this关键字去引用执行这个方法的对象,但是你可以使用其他对象的引用. 通常的,这些对象将会是专 ...
- 机器学习策略篇:详解为什么是ML策略?(Why ML Strategy?)
为什么是ML策略? 从一个启发性的例子开始讲,假设正在调试的猫分类器,经过一段时间的调整,系统达到了90%准确率,但对的应用程序来说还不够好. 可能有很多想法去改善的系统,比如,可能想去收集更多的训练 ...
- 学习go语言编程之面向对象
类型系统 类型系统是指一个语言的类型体系结构,一个典型的类型系统通常包含如下基本内容: 基础类型,如:byte.int.bool.float等 复合类型,如:数组.结构体.指针等 可以指向任意对象的类 ...
- 使用Java线程同步工具类CountDownLatch
java.util.concurrent.CountDownLatch是Java并发并发编程中的线程同步工具类,基于AQS(java.util.concurrent.locks.AbstractQue ...
- 混合类Mixins介绍
介绍 混合类是封装了一些通用行为的基类,旨在重用代码.通常,混合类本身并没有什么用,仅扩展这种类也行不通 因为在大多数情况下,它都依赖于其它类中定义的方法和属性.通过多继承,可将混合类与其它类一起使用 ...
- nginx中使用perl脚本来定制一些请求转发等等
http://t.zoukankan.com/carriezhangyan-p-9359708.html https://blog.csdn.net/weixin_28917223/article/d ...
- fatal: bad object refs/remotes/origin/xxx
解决方案: 1.项目的.git文件内的目录.git/logs/refs/remotes/origin/,删除该错误的本地远程分支: 2.执行git pull --rebase即可 类似错误信息例子: ...
- 【Azure Developer】Python 获取 Azure 中订阅(subscription)信息,包含ID, Name等
问题描述 在Azure AD中注册一个Applicaiton后,对其进行授权,能够查看所有订阅的ReadOnly权限,然后,是否可以同通过Python代码,在完成Authorization后(使用Cl ...
- 基于 Nebula Graph 构建百亿关系知识图谱实践
本文首发于 Nebula Graph Community 公众号 一.项目背景 微澜是一款用于查询技术.行业.企业.科研机构.学科及其关系的知识图谱应用,其中包含着百亿级的关系和数十亿级的实体,为了使 ...