在字符串匹配算法的前两讲,我们分别介绍了暴力算法BF算法,利用哈希值进行比较的RK算法,以及尽量减少比较次数的BM算法,没看过的小伙伴可以点击下方链接:
在字符串匹配算法的前两讲,我们分别介绍了暴力算法BF算法,利用哈希值进行比较的RK算法,以及尽量减少比较次数的BM算法。
KMP 算法可以说是字符串匹配算法中最知名的算法了,KMP 算法是根据三位作者(D.E.Knuth,J.H.Morris 和 V.R.Pratt)的名字来命名的,算法的全称是 Knuth Morris Pratt 算法,简称为 KMP 算法。
理论篇——帮你把KMP算法学个通透!(理论篇)_哔哩哔哩 (゜-゜)つロ 干杯~-bilibili
在此处,失配了,所以要进行回溯,i的初始位置变成第二个元素位置,j的初始位置变成第一个元素位置,再进行匹配
在主串A中查找模式串B的出现位置,其中如果A的长度是n,B的长度是m,则n > m。当我们暴力匹配时,在主串A中匹配起始位置分别是 0、1、2….n-m 且长度为 m 的 n-m+1 个子串。
串(string)(或字符串)是由零个或多个字符组成的有限序列,其中每个字符都来自某个字符表( Alphabet) Σ,比如 ASCII 字符集或 Unicode 字符集。 一般记为:
因为是由这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP
该算法的时间复杂度为O(n*m),其中n是字符串数组的长度,m是最长公共前缀的长度。
kmp算法用于字符串的模式匹配,也就是找到模式字符串在目标字符串的第一次出现的位置 比如 abababc 那么bab在其位置1处,bc在其位置5处 我们首先想到的最简单的办法就是蛮力的一个字符一个字符的匹配,但那样的时间复杂度会是O(m*n) kmp算法保证了时间复杂度为O(m+n)
也就是说,KMP算法是用来解决字符串匹配问题的,从一个主字符串text中寻找一个子字符串(模式字符串)pattern,看这个子串是否在主串中,比如对于text='abaacababcac'和pattern='ababc',子串是包含在主串中的,同时它在主串中的索引是5。
https://leetcode-cn.com/problems/implement-strstr/
假设我们有这样一个要求,一个字符串S,一个匹配字符串P,我们想知道匹配串P是否被包含在字符串S中,如果包含那它在S的什么位置上? 解决这个问题最简单的方法就是暴力匹配,匹配串中的一个元素匹配到了,就
对主串的每个字符作为子串开头,与要匹配的字符串进行匹配。对主串做大循环,每个字符开头做要匹配子串的长度的小循环,直到匹配成功或全部遍历完成为止串 S 与模式串 T 有部分相同子串时,可以简化朴素匹配算法中的循环流程。 KMP 中的关键就是求公共最长匹配前缀和后缀的长度。 从子串最长前缀和最长后缀开始求。最长也少于前面字符个数。
有两部分组成:并且是由大到小,倒着匹配 坏前缀:普通匹配只一位一位移动,移动规则为 si(坏字符的位置) xi(坏字符在匹配字符最后出现的位置) 都没有xi=-1 移动距离等于si-xi 好后缀:坏前缀有可能产生负数,所以还要利用好后缀来进行匹配,好后缀类似坏前缀如果匹配串中有和好后缀相同的子串 ,移动到最靠后的子串的位置,如果没有相同的子串,就需要在匹配的子串中,查找和前缀子串匹配最长的子串进行移动。
【问题描述】 对于字符串S和T,若T是S的子串,返回T在S中的位置(T的首字符在S中对应的下标),否则返回-1.
大家可能觉得 KMP 这个算法的名字很特别、很怪,因为 KMP 它并不是三个英文单词的开头,而是三个计算机科学家的名字。发明这个算法的三位计算机科学家分别为:Knuth、Morris、Pratt。第一个是大家都非常熟悉的 Donald Ervin Knuth (高德纳),他是《计算机设计艺术》的作者,也是编程界非常有名的一位老专家。然后 M 和 P 也都是当时比较著名的计算机专家,而 KMP 匹配算法就是他们三个一起研究出来的 。
KMP 算法可以说是我学过的算法里最让我印象深刻的一个算法了。初学 KMP 的时候真的是抓耳挠腮,硬啃了一下午的博客才勉强可以自己独立推一遍算法的整个流程。第二次学习 KMP 是为了在数据结构课上给同学们介绍这个算法,自己学和教会别人又是不一样的难度,于是我又重新学习了一遍,但这一次学习时有很多之前觉得很抽象的东西都突然茅塞顿开了,为了讲解的效果,我还反复推导了几次算法,确保讲课的流畅。第三次学习 KMP 是为了给集训队的学弟们讲这个算法,而竞赛更偏重于算法的应用,所以我在重新推演了一次算法后又找了一些经典例题。自此,对于 KMP 的理解可以说是挺明晰了。最近,我又学习了 AC自动机,很巧的是,AC自动机的思想和 KMP 是一样的,于是我又“被迫”重温了一遍 KMP ,既然那么有缘分,不如就写篇博客吧。
KMP 相关补充及内容来源和给我的一些启发 《代码随想录》 labuladong-有限状态机之 KMP 字符匹配算法 ---- 我想对你说: 其实我感觉,写完本文我其实还不是特别透彻,也许在三刷或者更多刷的时候,或者说也许在未来的某一刻我会突然顿悟,到时候我可能还会更新一篇文章。 希望这篇文章能够给你一些启发。 ---- 前言: 以下内容中,我们称要匹配的字符串为模式串,使用模式串去匹配看是否存在该子串的叫文本串。 即,使用模式串在文本串中匹配,看文本串中
由三位前辈发表的一个模式匹配算法,可以大大避免重复遍历的情况,称之为克努特-莫里斯-普拉特算法,检查 KMP 算法。
KMP算法是我们数据结构串中最难也是最重要的算法。难是因为KMP算法的代码很优美简洁干练,但里面包含着非常深的思维。真正理解代码的人可以说对KMP算法的了解已经相当深入了。而且这个算法的不少东西的确不容易讲懂,很多正规的书本把概念一摆出直接劝退无数人。这篇文章将尽量以最详细的方式配图介绍KMP算法及其改进。文章的开始我先对KMP算法的三位创始人Knuth,Morris,Pratt致敬,懂得这个算法的流程后你真的不得不佩服他们的聪明才智。
第二轮,模式串向后挪动一位,和主串的第二个等长子串比较,发现第0位字符不一致:
KMP算法由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。
3.KMP算法—这里借鉴宫水三叶大佬的讲解 具体详情可以看原文 KMP 算法是一个快速查找匹配串的算法,它的作用其实就是本题问题:如何快速在「原字符串」中找到「匹配字符串」。 上述的朴素解法,不考虑剪枝的话复杂度是 O(m * n) 的,而 KMP 算法的复杂度为 O(m + n)。 KMP 之所以能够在 O(m + n)O(m+n) 复杂度内完成查找,是因为其能在「非完全匹配」的过程中提取到有效信息进行复用,以减少「重复匹配」的消耗。
相对于那些要对树、图进行操作的算法,这个算法要处理的是一维线性的字符序列。看起来似乎简单不少,那么算法难度会更低吗?让我们来看看。
Kmp算法是一种效率极高的串匹配算法,适用这样的场景,在给定文本串text中查找是否含有指定的模式串pattern。
给定一个字符串 s,你可以通过在字符串前面添加字符将其转换为回文串。找到并返回可以用这种方式转换的最短回文串。
这篇文章主要是总结一下kmp算法。所以就不写暴力遍历的逻辑了。这个算法属实是让我看了挺长时间,各种讲解博客是一点也看不进去(不是写的不详细,而是总感觉写的乱七八糟很复杂),最长公共前缀一直没理解其作用,不过反反复复的刷对应的讲解视频,卒或有所闻。
在解决字符串匹配问题中,若不使用python内置函数,大部分时候会想到使用BF(暴力循环)算法来解决。然而,这样会产生一个问题:算法的时间复杂度过高,匹配的字符串过长,往往会导致计算结果超时。如果使用KMP算法就能减少不必要的循环匹配计算,极大的减少算法的时间复杂度。
https://leetcode-cn.com/problems/repeated-substring-pattern/
子串的定位操作通常称为串的模式匹配,它求的是子串(常称模式串)在主串中的位置。下面给出一种不依赖于其他串操作的暴力匹配算法。
Kunth-Morris-Pratt字符串查找算法。在一个字符串中查找一个词出现的位置。
常关注本blog的读者朋友想必看过此篇文章:从B树、B+树、B*树谈到R 树,这次,咱们来讲另外两种树:Tire树与后缀树。不过,在此之前,先来看两个问题。 第一个问题: 一个文本文件,大约有一万行,每行一个词,要求统计出其中最频繁出现的前10个词,请给出思想,给出时间复杂度分析。
KMP算法,又称模式匹配算法,能够在线性时间内判定字符串 A[1~N]是否为字符串B[1~M]的子串,并求出字符串A在字符串B中各次出现的位置。
谈到字符串问题,不得不提的就是 KMP 算法,它是用来解决字符串查找的问题,可以在一个字符串(S)中查找一个子串(W)出现的位置。KMP 算法把字符匹配的时间复杂度缩小到 O(m+n) ,而空间复杂度也只有O(m)。因为“暴力搜索”的方法会反复回溯主串,导致效率低下,而KMP算法可以利用已经部分匹配这个有效信息,保持主串上的指针不回溯,通过修改子串的指针,让模式串尽量地移动到有效的位置。
如果 b[k] != b[j] , 则我要在前面部分里寻找能和包含 b[j] 的后缀匹配的最长前缀子串; b[k] 前面的最长匹配前缀长度就是 next[k],那么其后面一个字符就是 b[ next[k] ],如果它等于b[j],那么next[j+1] = next[k] + 1 参考文献
我们看看当我进行完前面的操作后,是否需要继续重i = 2, j = 1开始看起呢
Problem Description It is well known that AekdyCoin is good at string problems as well as number theory problems. When given a string s, we can write down all the non-empty prefixes of this string. For example: s: “abab” The prefixes are: “a”, “ab”, “aba”, “abab” For each prefix, we can count the times it matches in s. So we can see that prefix “a” matches twice, “ab” matches twice too, “aba” matches once, and “abab” matches once. Now you are asked to calculate the sum of the match times for all the prefixes. For “abab”, it is 2 + 2 + 1 + 1 = 6. The answer may be very large, so output the answer mod 10007.
有句话很有趣:Stay hungry, stay foolish. 个人根据对这句话的理解 以一个有强烈求知欲的小白的角度,用提问解答的方式组织全文,以此发现自己知识图谱的不足并积极学习新的知识。
我们在平时的软件开发,尤其是嵌入式开发,字符串匹配是非常重要的一个算法。而目前常用的字符串匹配算法有很多,下面就来介绍几个。
Ackerman函数有A(n,m)有两个独立的整变量m\ge0,n\ge0,其定义如下
Z algorithm是我今天做leetcode的时候偶然得知的一个用于字符串匹配的经典算法,我说怎么一个我几乎毫无解题思路的题目别人人均2分钟搞定,也是把我惊到了……
字符串哈希是字符串模式匹配中的一个经典做法,具体概念在上一章 “0x14 哈希” 中讲过了
为解决上述问题,从1985年起在IP地址中又增加了一个“子网号字段”,使两级IP地址变成为三级IP地址,它能够较好地解决上述问题,并且使用起来也很灵活。这种做法叫作划分子网(subnetting) [RFC 950],或子网寻址或子网路由选择。 划分子网已成为因特网的正式标准协议。
字符串匹配问题 首先我们先把问题明确一下,给定两个字符串P[1..P.len]和S[1..S.len],找出P在S中第一次出现的位置L,即最小的L满足P[1..len]=S[L..L+len-1]。例如”HA”在”WAHAHA”中第一次出现的位置是3(这一节约定下标都是从1开始) 暴力算法 从小到大枚举L,然后判断P[1..len]=S[L..L+len-1]的条件是不是满足;不满足就+1试下一个L。伪代码如下: Match(P,S) For L = 1...S.len - P.len + 1
1977 年,德克萨斯大学的 Robert S. Boyer 教授和 J Strother Moore 教授发明了一种新的字符串匹配算法:Boyer-Moore 算法,简称 BM 算法。
我们使用某些算法来进行搜索过程。模式搜索的复杂性因算法而异。在数据库中执行搜索时它们非常有用。模式搜索算法对于在较大字符串的子字符串中查找模式非常有用。这个过程可以使用我们将在本文章中讨论的各种算法来完成。
字符串匹配是我们在编程中常见的问题,其中从一个字符串(主串)中检测出另一个字符串(模式串)是一个非常经典的问题,当提及到这个问题时我们首先想到的算法可能就是暴力匹配,下面的动图就展示了暴力匹配的流程。
首先,我们将描述一种查找一组字符串的最长公共前缀 LCP(S_1 \ldots S_n)LCP(S1…Sn) 的简单方法。 我们将会用到这样的结论:
领取专属 10元无门槛券
手把手带您无忧上云