kmp

KMP算法

人走茶凉 提交于 2020-02-18 09:26:36
一、算法背景 给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题。 Knuth-Morris-Pratt 算法(简称 KMP)是解决这一问题的常用算法之一,这个算法是由高德纳(Donald Ervin Knuth)和沃恩·普拉特在1974年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终三人于1977年联合发表。 在继续下面的内容之前,有必要在这里介绍下两个概念: 真前缀 和 真后缀 。 由上图所得, "真前缀"指除了自身以外,一个字符串的全部头部组合;"真后缀"指除了自身以外,一个字符串的全部尾部组合。 二、暴力匹配 这个算法的复杂度是O(n*m) 1 // n是P的长度,m是S的长度,返回P在S中出现的次数 2 int solve(char P[],int n,char S[],int m) // P是模式串,S是主串 3 { 4 int ans = 0; 5 int i,j; 6 for (i=0;i+n<=m;i++) 7 { 8 for (j=0;j<n;j++) 9 { 10 if (S[i+j] != P[j]) 11 break; 12 } 13 if (j == n) 14 ans++; 15 } 16 return ans; 17 } 三:KMP字符串匹配算法

KMP算法小结

一世执手 提交于 2020-02-16 08:33:18
KMP算法为字符串匹配时用,能够实现O(n)的复杂度完成匹配。 我们考虑一般的暴力匹配,其复杂度为O(nm)。 然而它的可以优化的。 任何一种优化都是能够充分运用已拥有的信息,KMP算法亦然。 我们设模板串 a ,待匹配串 b 。 它通过一个关于字符串 b 的 next 数组,告诉你当匹配到某位失效的时候,你可以从 b 串之前的某一位继续匹配当前 a 串的某位,而不必从 b 串第一位开始匹配。 具体的求法,可以用 b 串来匹配 b 串来求得。 在这里的 next 数组,个人理解为当第 i 位可以追溯到第 next[i] 位,即若在第 i+1 位匹配失败时,我们可以回到 next[i] 位继续匹配。在这里,我们令 s[i] 为 b 串的前 i 位字符串,则 s[next[i]-1] 是 s[i] 的最大前后缀(就是 s[i] 的后缀的最长前缀,如 aba 是 abaaaabb aba 的最大 前 后缀 ,当最后的 a 的后一位匹配失败时,我们就回到第3+1位继续匹配 ) 1 #include<iostream> 2 #include<string> 3 using namespace std; 4 string qwq,qaq; 5 int next[1000008],m,n; 6 void makenext(){ 7 next[0]=0; 8 int k=0; 9 for (int

kmp算法总结

安稳与你 提交于 2020-02-15 05:44:12
转载分享,是我看到的最好懂的kmp讲解了!!谢谢原作,贴上链接 原作链接 KMP算法 KMP算法是一种线性时间复杂度的字符串匹配算法,它是对BF(Brute-Force,最基本的字符串匹配算法)的改进。对于给定的原始串S和模式串T,需要从字符串S中找到字符串T出现的位置的索引。KMP算法由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为Knuth–Morris–Pratt算法,简称KMP算法。在讲解KMP算法之前,有必要对它的前身–BF算法有所了解,因此首先将介绍最朴素的BF算法。 一:BF算法简介 如上图所示,原始串S=abcabcabdabba,模式串为abcabd。(下标从0开始)从s[0]开始依次比较S[i] 和T[i]是否相等,直到T[5]时发现不相等,这时候说明发生了失配,在BF算法中,发生失配时,T必须回溯到最开始,S下标+1,然后继续匹配,如下图所示: 这次立即发生了失配,所以继续回溯,直到S开始下表增加到3,匹配成功。 容易得到,BF算法的时间复杂度是O(n*m)的,其中n为原始串的长度,m为模式串的长度。BF的代码实现也非常简单直观,这里不给出,因为下一个介绍的KMP算法是BF算法的改进,其时间复杂度为线性O(n+m),算法实现也不比BF算法难多少。 二:KMP算法 前面提到了朴素匹配算法,它的优点就是简单明了

串模式匹配--KMP和BF

陌路散爱 提交于 2020-02-11 00:54:51
1、暴力匹配算法BF 假设现在我们面临这样一个问题:有一个文本串S,和一个模式串P,现在要查找P在S中的位置,怎么查找呢? 如果用暴力匹配的思路,并假设现在文本串S匹配到 i 位置,模式串P匹配到 j 位置,则有: 如果当前字符匹配成功(即S[i] == P[j]),则i++,j++,继续匹配下一个字符; 如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0。相当于每次匹配失败时,i 回溯,j 被置为0。 理清楚了暴力匹配算法的流程及内在的逻辑,咱们可以写出暴力匹配的代码,如下: int ViolentMatch(char* s, char* p) { int sLen = strlen(s); int pLen = strlen(p); int i = 0; int j = 0; while (i < sLen && j < pLen) { if (s[i] == p[j]) { //①如果当前字符匹配成功(即S[i] == P[j]),则i++,j++ i++; j++; } else { //②如果失配(即S[i]! = P[j]),令i = i - (j - 1),j = 0 i = i - j + 1; j = 0; } } //匹配成功,返回模式串p在文本串s中的位置,否则返回-1 if (j == pLen) return i - j;

KMP例题—最小循环节—Lintcode1365—C++

删除回忆录丶 提交于 2020-02-10 13:10:07
本题是Lintcode上面的 KMP例题,困难属性。。。还是“限免题”,无力吐槽。 抄个题先— 1365. 最小循环节 中文English 给出一个int的数组 array, 求这个数组的最小循环节的长度。 样例 样例1 输入: [1,2,1,2,1,2] 输出: 2 说明: 最小循环节为[1,2],长度为2。 样例2 输入: [1,2,1,2,1] 输出: 2 说明: 最小循环节为[1,2],长度为2。最后一个2虽然没有给出,但是我们还是认为循环[1,2]。 样例3 输入: [1,2,1,2,1,4] 输出: 6 说明: 最小循环节为[1,2,1,2,1,4],长度为6。 注意事项 数组大小不超过 100000 。 每个数int范围内。 上代码!!!!先看下面的两个AC代码 代码1: class Solution { public: /** * @param array: an integer array * @return: the length of the minimum cycle section */ int minimumCycleSection(vector<int> &array) { // Write your code here int len=array.size(); vector<int>dp(len,0); dp[0]=0; for(int i=1;i

kmp算法

给你一囗甜甜゛ 提交于 2020-02-10 04:59:49
数据结构 —KMP   参考文章 https://www.cnblogs.com/wuwangchuxin0924/p/5986243.html https://www.cnblogs.com/ciyeer/p/9035072.html KMP算法用于解决两个字符串匹配的问题,但更多的时候用到的是 next数组的含义,用到 next数组的时候,大多是题目跟前后缀有关的 。 首先介绍 KMP算法:(假定 next数组已经学会,后边 next数组会在介绍) 上图 T为主链, P为模板链,要求 P在 T中是否出现,出现就返回位置。 朴素算法会顺序遍历,比较第一次的时候 p[0]处失配,然后向后移动继续匹配。数据量大的时候这么做肯定是不可行的。所以这里就会有 KMP算法!在一次失配之后, KMP算法认为这里已经失配了,就不能在比较一遍了,而是将字符串 P向前移动 (已匹配长度 -最大公共长度 )位,接着继续比较下一个位置。这里已匹配长度好理解,但是最大公共长度是什么呐?这里就出现了 next数组, next数组: next[i]表示的是 P[0-i]最大公共前后缀公共长度。这里肯定又有人要问了, next数组这么奇葩的定义,为什么就能算出来字符串需要向后平移几位才不会重复比较呐? 上图中红星标记为例,此时在 p[4]处失配,已匹配长度为 4,而 next[3]=2(也就是

KMP

岁酱吖の 提交于 2020-02-09 00:05:39
KMP:子串在对父串每一次匹配失败时,右移位数的优化。 右移位数 = 已匹配的字符数 - 对应的部分匹配值 前缀:字串中,除了最后一个字符,包含第一个字符的全部字串组合 后缀:字串中,除了第一个字符,包含最后一个字符的全部字串组合 部分匹配值:前缀和后缀所有字串中包含有共同字符的字符个数 部分匹配表:首字符开始,下标对应于KMP数组下标,每个KMP数组元素值为首字符到当前字符字串的匹配值。 eg:根据子串KMP推导右移个数     ETCABCDABETC    ABCDABD     子串第7位匹配失败,查表PMT[6],右移位数 = 6 - PMT[6] = 4,右移4位。 eg:手动推导子串KMP     子串:ABCDABD      KMP实现:      1. PMT[0] = 0;子串第一个字符组成的字串的前后缀匹配值都为0。如果可选L都为0,直接对比首尾元素。      2. 从PMT[1]开始推导,LL为当前计算子串的前后交集元素最长长度,如果sub_str[LL] = sub_str[i],则当前LL加 1      3. 如果sub_str[LL] != sub+str[i],则LL = KMP[LL - 1],直到sub_str[LL] = sub_str[i]。 实现代码: int* String::make_mtp(const char* up_str)

关于KMP算法

有些话、适合烂在心里 提交于 2020-02-07 09:26:48
KMP 算法是非常经典的字符串匹配算法,而且有可能是最经典的一个。同时它也是非常典型的一种优化算法,它把原本暴力法 O( mn ) 的最坏复杂度降低到了 O( m+n )(虽然实际上暴力法的执行复杂度期望依然是线性的),其思想非常具有典型性和可借鉴性,值得好好学习。 1 基本思想 KMP 算法的基本思想是,借助一个预先计算好的数组 pi ,在匹配了一定数量的模式的情况下,遇到不匹配的字符时,不像暴力法那样将待匹配的文本下标从上一次匹配的地方向后移动一个位置,并将已匹配的模式个数清零,而是利用已经匹配部分的信息,迅速跳过那些不可能匹配成功的文本开头,减少了暴力法中一些不必要的盲目搜索。 比如,对于模式 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 a b a b a b c a b c a b c d b c d b c d 如果从文本中的某一个字符开始,匹配到6号字符c时,出现了不匹配,此时已经匹配了6个字符。如果再从文本中下一个字符b开始,从模式的第0号字符开始继续尝试,就是暴力法的思想。而 KMP 算法比暴力法先进的地方就在于,它利用 模式 已匹配部分的信息,跳过那些已遍历的文本中不可能匹配的开头,直接进入有可能会产生匹配的文本开头,并更新相应的已匹配字符长度。比如,匹配到6号字符时,出现不匹配

kmp算法的自我理解

萝らか妹 提交于 2020-02-07 09:26:31
序:很久没做算法题了,为了回顾一下自己的算法知识,方便下次理解,特地记录自己一些对一些算法的理解。 约定: 模式串 ababcd 文本串 abababcd 用 M 代表模式串, W 代表文本串 kmp算法包括两个部分,1.计算模式串的next数组。 2.kmp主程序,模式串与主串(即文本串)的匹配。 Next数组 next[i]表示字符串第i个字符可匹配的最近的下标(挺拗口的),作用是记录已经遍历过的字符内的信息。 先看计算next数组的程序, private static int[] getNext(char[] str) { int length = str.length; int[] next = new int[length]; next[0] = -1; int k = -1; for(int i=1; i<length; i++) { while(k > -1 && str[i] != str[k+1]){ k = next[k]; } if(str[i] == str[k+1]) { k++; } next[i] = k; } return next; } 字母下方即是模式串的next数组 a b a b c d -1 -1 0 1 -1 -1 从结果来看,我们可以看到next[3] = 1,含义是它的可匹配的最近的下标是1。其实从这时候来看还是觉得没什么作用

KMP字符串匹配算法

僤鯓⒐⒋嵵緔 提交于 2020-02-07 09:22:57
昨天意外的翻开一本搜索引擎的书,看到了KMP算法,很早以前就听过KMP算法,但是没有深究,最近在搞搜索,所以想深入学习一下 KMP算法 。KMP算法是一种改进的字符串匹配算法。KMP算法的核心是通过匹配表来提高匹配效率,理解了匹配表就基本理解了KMP算法。核心思想是利用已经得到的部分匹配信息来进行后面的匹配过程。我认为优秀算法的根本是减少不必要的重复计算从而提升效率。 介绍两个概念: 前缀:除字符串的最后一个字符外,所有前缀组合 后缀:除了字符串的第一个字符外,所有后缀组合 例如:Google,前缀:G、Go、Goo、Goog、Googl 后缀:o、oo、oog、oogl、oogle 那么匹配表怎么算呢,找到” 前缀和后缀集合中最长匹配的字符串的长度 “。 例如:abababca a的前缀后缀都为空 L=0 ab的前缀为a后缀为b L=0 aba的前缀a、ab后缀a、ba,L=1 abab的前缀a、ab、aba后缀b、ab、bab,L=2 ababa的前缀a、ab、aba、abab后缀baba、aba、ba、a,L=3 ababab的前缀a、ab、aba、abab、ababa后缀babab、abab、bab、ab、b,L=4 abababc的前缀a、ab、aba、abab、ababa、ababab后缀bababc、ababc、babc、abc、bc、c,L=0