kmp

KMP(模板)

青春壹個敷衍的年華 提交于 2019-12-14 01:35:10
简单理解 首先kmp有两部分组成 第一部分 next数组 什么是next数组 通俗的讲就是 子串自己对自己的前后缀匹配 举个栗子 子串:ABABCABAA 对应的next 第二部分就是kmp了 其实跟第一部分很像,只不过是把对象换成了母串 即子串对母串的前缀匹配 落谷有一kmp模板题 点这里 # 下面是蒟蒻的代码以及巨佬的代码 //鄙人的代码,只能过70%的样例,剩下的超时了很尴尬 # include <iostream> # include <stdio.h> # include <string.h> using namespace std ; char a [ 2222222 ] , b [ 2222222 ] ; int p [ 2222222 ] ; void next ( int lenb ) { p [ 0 ] = 0 ; //第一个为0 int i = 1 , len = 0 ; //i是位置,len是长度 while ( i < lenb ) //自我匹配 { if ( b [ i ] == b [ len ] ) { len ++ ; p [ i ++ ] = len ; } else { if ( len > 0 ) //防止出现死循环 len = p [ len ] ; //跳回去 else p [ i ++ ] = len ; } } } void move

彻底搞懂KMP,一篇就够了

南楼画角 提交于 2019-12-13 07:24:49
前言: 看毛片算法漫画讲解超幽默有爱~ 一,KMP算法解决什么类型的问题 String str1 = "bacbababadababacambabacaddababacasdsd" ; String str2 = "ababaca" ; 由以上字符串我们知道,str1有两处包含str2 分别在str1的下标为10,26的位置 “bacbababad * * ababaca * * mbabacadd * * ababaca * * sdsd” ; 二,算法讲解与说明 一般匹配字符串时,我们从目标字符串str1(假设长度为n)的第一个下标选取和str2长度(长度为m)一样的子字符串进行比较,直到str1的末尾(实际比较时,下标移动到n-m)。这样子的复杂度就是O(n*m)。而KMP算法的复杂度可以优化为O(n+m) 简化时间复杂度的原因:充分利用了目标字符串str2的性质(比如里面部分的字符串的重复性,即使不存在重复字段,在比较时实现最大的移动量。 三,考察目标字符串str2 ababaca 这里我们先要计算一个长度为m的转移函数next。next数组的含义就是一个固定字符串的最长前缀和最长后缀相同的长度。 比如:abcjkdabc,那么这个数组的最长前缀和最长后缀相同的话必然是abc。 cbcbc,这个数组的最长前缀以及最长后缀相同就是cbc。 abcbc

KMP算法的改进

纵然是瞬间 提交于 2019-12-12 14:23:00
目录 KMP算法的改进点 nextval数组的手动求解 nextval数组的程序求解 KMP算法的改进点 在原始的KMP算法中,子串已经不会回退到起始点,但是还有一种特殊情况,首先看下表(已经求得next数组)。 模式串 A A A A A B j 0 1 2 3 4 5 next[j] -1 0 1 2 3 4 如果当j等于4的时候,发生不匹配,因为next[4]=3,则需要将j回溯到3进行比较;又因为next[3]=2,则又要将j回溯到2的位置进行比较,j需要一次在4,3,2,1,0的位置上进行比较,而模式串在0到4上的内容是相等的,因此比较聪明的做法是当在j=4发生不匹配的时候,直接将j回溯到0,直接跳过1到3的多余的比较,这就是KMP算法改进的切入点。 nextval数组的手动求解 对于手动求解nextval数组,先可以求出next数组,然后再求nextval数组,首先先给出大家一个实例,见下表: 模式串 A B A B A A B j 0 1 2 3 4 5 6 next[j] -1 0 0 1 2 3 1 nextval[j] -1 0 -1 0 -1 3 0 参照上表,给出nextval数组的一般步骤: 求出next数组; 当j=1时,另nextval[j]=-1,作为特殊标记; (记模式串为p)当p[j]不等于p[next[j]]时,另nextval[j]=next

KMP子字符串查找算法分析与实现

戏子无情 提交于 2019-12-11 06:10:09
【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>> 原创博客,转载请注明 http://my.oschina.net/BreathL/blog/137916 子字符串查找,是程序设计的一个基本且普遍的问题。通常情况下子字符串查找不需要特别的设计,一是由于执行的次数不多,二是查找字符串一般也较短,所以不会形成性能的瓶颈;但如果你的程序里有大量的查找或长字符串的子串查找,也许就需要考虑特别的设计已保证程序的效率。 暴力查找算法: 大部分语言默认的子字符串查找都是使用的暴力查找算法,思路很简单,就是逐个取出 待 查找的字符串的字节,然后依次和被包含的子字符串的字节比较,从以第一个开始,若相等,则各自取下一个继续比较;若不相等,则 待 查找的字符串回退回去到起始比较处的下一个字节,而子字符串从头开始取,然后以此循环的比较。 可以优化: 它的算法复杂度是 N*M 这个量级的,但有个问题是:当匹配失败后, 待 查找的字符串回退回去到起始比较处的下一个字节,而子字符串从头开始取时,紧接着的几步比较可能是 多余的计算。因为前X已经匹配上了,说明临近X个字节已知了,那就可以根据已知的情况去掉一些重复的比较,这就KMP子字符串查找算法的优化原理。这么说可能有些模糊,举个例子: 带查找字符串: F Y Y Y Y U H N Z Y Y Y Y 目标字符串: F Y Y Y Y M

KMP算法

爱⌒轻易说出口 提交于 2019-12-10 21:31:30
大名鼎鼎的KMP算法,当初考研时也没好好看,最近才搞懂,惭愧。 public class KMP { public static int[] GetNextArray(char[] str2){//str2为子串 if(str2.length==1) return new int[]{-1}; int[] next=new int[str2.length]; next[0]=-1; next[1]=0; int i=2; int cn=0; while(i<next.length){ if(str2[i-1]==str2[cn]){ // next[i]=next[i-1]+1; // cn++; // i++; next[i++]=++cn; }else if(cn>0){ cn=next[cn]; }else{ next[i++]=0;//此时cn一定为0 } } System.out.println("next数组:"+Arrays.toString(next)); return next; } public static int KMP(String s_1,String s_2){//s1为主串,s2为子串 if(s_1==null||s_2==null||s_2.length()<1||s_1.length()<s_2.length()) return -1; char

今天学习了下 KMP算法

杀马特。学长 韩版系。学妹 提交于 2019-12-10 05:31:16
即: Knuth-Morris-Pratt 字符串查找算法,即查找字符串B在字符串A中的位置 目标字符串(A):target adczdfdadfadf 查找的子串(B ): pattern adfaerw ------------------------- 普通比较算法 一个一个比较,匹配失败时,又从pattern的头开始,并且 target的指针也回退。 比如:第一轮(从A[0]开始) 匹配 到 A[2]!=B[2] 时,会继续第二轮,此时A的指针已指到C,但第二轮又会退到1,继续比较A[1],A[2] 如果,可以利用 B的一些特性,就可以不用再重复比较已比较过的,相反移动B就可以,而不用回退A的搜索指针。而移动的距离即是我们要查找的值。 寻找模式特性(最大首尾匹配值): 字符串S,长度L(>0),起始下标0 满足 S 0 S 1 ....S k =S L-1-k S L-k .....S L-1 的最大K值 即为 我们要找的K值,没有或L=1则为起始下标减一。 利用:假设我们已经比较到B下标的L,即已匹配了B的位置0~L-1的子串C,发现位置L处不匹配,那么我们将B移动,m(子串C的最大首尾匹配值)个位置,这样我们已经匹配的就可以不用再匹配了。 KMP算法即是采用上面的这种方法 KMP算法 准备工作: 计算B所有从头开始的子串的最大k值 算法开始: (假设起始下标为x

KMP算法的next[]数组通俗解释

≯℡__Kan透↙ 提交于 2019-12-10 00:38:15
前言 本文是对KMP核心部分NEXT数组的构建方法说明,KMP整体分析的文章可以参考下面的链接。 http://my.oschina.net/u/572632/blog/277548 概述 我们在一个母字符串中查找一个子字符串有很多方法。KMP是一种最常见的改进算法,它可以在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度。 当然我们可以看到这个算法针对的是子串有对称属性,如果有对称属性,那么就需要向前查找是否有可以再次匹配的内容。在KMP算法中有个数组,叫做前缀数组,也有的叫next数组,每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符,当然它描述的也是子串的对称程度,程度越高,值越大,当然之前可能出现再匹配的机会就更大。这个next数组的求法是KMP算法的关键,但不是很好理解,我在这里用通俗的话解释一下,看到别的地方到处是数学公式推导,看得都蛋疼,这个篇文章仅贡献给不喜欢看数学公式又想理解KMP算法的同学。 分析 用一个例子来解释,下面是一个子串的next数组的值,可以看到这个子串的对称程度很高,所以next值都比较大。 一 逐个查找对称串 这个很简单,我们只要循环遍历这个子串,分别看前1个字符,前2个字符,3个... i个 最后到15个。 第1个a无对称,所以对称程度0 前两个ag无对称,所以也是0 依次类推前面0

KMP

☆樱花仙子☆ 提交于 2019-12-09 16:33:08
详细讲解 例题 #include<bits/stdc++.h> using namespace std; string a,b; int nest[1000005]; int m,n; void q_next() { int k=0; for(int i=2; i<=n; i++) { while(k>0&&b[i]!=b[k+1]) k=nest[k]; if(b[i]==b[k+1]) k++; nest[i]=k; } } int main() { cin>>a; cin>>b; m=a.length(); n=b.length(); a=' '+a; b=' '+b; q_next(); int k=1; for(int i=1; i<=m; i++) { while(k>0&&a[i]!=b[k+1]) k=nest[k]; if(a[i]==b[k+1]) k++; if(k==n) { cout<<i-n+1<<"\n"; k=nest[k]; } } for(int i=1; i<=n; i++) cout<<nest[i]<<" "; return 0; } 来源: https://www.cnblogs.com/mxy2004/p/12011771.html

Luogu2375 [NOI2014]动物园 (KMP)

纵然是瞬间 提交于 2019-12-09 13:03:40
写炸,上网,不同KMP形态。 无力,照该,一换写法就过。 横批:我是垃圾 求 \(next\) 时 \(DP\) 出 \(num\) ,路径压缩防卡 \(n^2\) AC #include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #define R(a,b,c) for(register int a = (b); a <= (c); ++ a) #define nR(a,b,c) for(register int a = (b); a >= (c); -- a) #define Max(a,b) ((a) > (b) ? (a) : (b)) #define Min(a,b) ((a) < (b) ? (a) : (b)) #define Fill(a,b) memset(a, b, sizeof(a)) #define Abs(a) ((a) < 0 ? -(a) : (a)) #define Swap(a,b) a^=b^=a^=b #define ll long long #define ON_DEBUG #ifdef ON_DEBUG #define D_e_Line printf("\n\n----------\n\n") #define D

POJ1961Period(kmp+循环节)

社会主义新天地 提交于 2019-12-08 13:10:33
传送门 题目大意:输出字符串所有前缀的循环节个数,下标从1开始,i 和1-i循环节的个数 题解:网上摘得 KMP最小循环节、循环周期: 定理:假设S的长度为len,则S存在最小循环节,循环节的长度L为len-next[len],子串为S[0…len-next[len]-1]。 (1)如果len可以被len - next[len]整除,则表明字符串S可以完全由循环节循环组成,循环周期T=len/L。 (2)如果不能,说明还需要再添加几个字母才能补全。需要补的个数是循环个数L-len%L=L-(len-L)%L=L-next[len]%L,L=len-next[len]。 代码: #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define N 1000009 using namespace std; int n,len; char s[N]; int nxt[N]; void getnext() { memset(nxt,0,sizeof(nxt)); for(int i=2,j=0;i<=len;i++) { while(s[i]!=s[j+1]&&j) j=nxt[j]; if(s[i]==s[j+1]) nxt[i]=++j; } } int main() { while(1)