KMP模板及总结

KMP是一种字符串匹配算法,它在时间复杂度上较暴力匹配算法由很大的优势。比如我要找字符串S中是否存在子串P,如果暴力匹配的话,则时间复杂度为O(n*m),而kmp算法时间复杂度为O(n+m)

这里我们有一个辅助的数组next[](先别管怎么求出来的),next[i]含义是模式串P中[0....i-1]这一段的长度小于这段字符串的长度的最长公共前缀(比如ababa,公共前缀就是aba)。

好,那我们接下来讲一下kmp算法的具体操作:

假设,我们开始有字符串S:ababaaba   模式串P:abaa

对应next[i](0=<i<=len(P))的值为:

next[0]=-1 (无)

next[1]=0  (a)

next[2]=0  (ab)

next[3]=1  (aba)

next[4]=1  (abaa)

好,有了next数组,我们接下来进行匹配,设i=0是S上的当前匹配位置,j=0是P上的当前匹配位置。

第一次匹配,一直到i=3,j=3时匹配失败,令j=nxet[j]继续匹配。(为什么可以令j=next[j]?简单来说P[0...0]等于P[2...2],而通过第一次匹配,我们知道P[2..2]等于S[2...2],所以可以跳过这一段不用重复匹配,具体原理接下来解释)

第二次匹配,从i=3,j=1开始,匹配成功,获得答案。

大概过程就是这样。

下面按我自己的理解,解释一下kmp的原理:

如下图所示(图很丑,我真的不知道怎么画图),S[0...i]和P[0...i]匹配上了,匹配到i+1时匹配失败。

好,我们仔细分析一下,设L=nxet[i],则P[0...L]等于P[i-L...i],又因为通过刚才的匹配,我们确定了S[0...i]等于P[0...i],所以在S上也有一段对应的S[L-i...i]=P[L-i..i]=P[0...L]。

所以第二次匹配时,我们可以直接将P挪动,使P[0...L]对应S[L-i...i],直接从i+1开始匹配(即上文中的j=next[j]),如下图所示:

P[0...L]=S[L-i..i]可以理解,但是为什么可以直接挪过来呢,忽略了可能出现的情况怎么办?比如说下图这样的情况:

是否会有一段这样的字符串S[k..k+m]被我们忽略呢?若有的话,那显然k的位置更优因为i-k>L更有利于我们减少重复匹配。

实际上是不存在的,很容易知道,若存在一段长度大于L的S[k...i]=P[0...i-k+1]那么因为P[0...i]=S[0...i]肯定会有一段P[k..i]=S[k..i]=P[0..i-k+1],即P[0...i-k+1]和P[k..i]是一段公共前缀。

但是前面我们说了L=next[i]表示P[0...i]的最长公共前后缀,而上述的情况存在则说明有比L更长的公共前缀,这就矛盾了,所以S[k...k+m]这样的字符串是不存在的。

好了,这下kmp的原理我们知道了,接下来说next数组是如何构造的:

模板代码:

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 using namespace std;
 6 const int N=1e6+5;
 7
 8 int nxt[N];
 9 char s[N],t[N];
10
11 //获得next数组
12 void getnext(char *s,int len){
13     int i,j;
14     i=0,j=nxt[0]=-1;
15     len=strlen(s);
16     while(i<len){
17         while(j!=-1&&s[i]!=s[j])
18             j=nxt[j];
19         i++,j++;
20         nxt[i]=j;
21     }
22 }
23
24 //返回第一次匹配成功的位置
25 int kmp(char *s,char *t){
26     int i,j,len,len2;
27     len1=strlen(s);
28     len2=strlen(t);
29     getnext(t,len2);
30     i=j=0;
31     while(i<len){
32         while(j!=-1&&s[i]!=t[j])
33             j=nxt[j];
34         i++,j++;
35         if(j==len2)
36             return i-len2+1;
37     }
38     return -1;
39 }

KMP常见题型:

一、字符串匹配,求出模式串P在S中是否存在,输出第一次出现的位置

HDU 1171

二、求模式串P在S中的出现次数(注意分可重和不可重的情况)

HDU 1686

三、求所有公共前后缀(既是前缀又是后缀)

POJ 2752

四、求字符串循环节

HDU 3746(找最小循环节)

FZU 1901(求所有循环节)

五、求所有S的前缀在S中出现次数之和

HDU 3336

六、最大最小表示

HDU 3374

原文地址:https://www.cnblogs.com/fu3638/p/8505038.html

时间: 2024-10-16 14:36:53

KMP模板及总结的相关文章

HDU 1711 Number Sequence(KMP模板)

http://acm.hdu.edu.cn/showproblem.php?pid=1711 这道题就是一个KMP模板. 1 #include<iostream> 2 #include<cstring> 3 using namespace std; 4 5 const int maxn = 1000000+5; 6 7 int n,m; 8 9 int next[maxn]; 10 int a[maxn], b[maxn]; 11 12 void get_next() 13 { 1

POJ Oulipo(KMP模板题)

题意:找出模板在文本串中出现的次数 思路:KMP模板题 #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<map> #include<queue> #include<stack&

[POJ 3461] Oulipo &amp; KMP模板

Oulipo Time Limit: 1000ms, Memory Limit: 65536K Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a member of the Oulipo group. A quote from the book: Tout avait Pair normal, mai

hdu 1711 KMP模板题

// hdu 1711 KMP模板题 // 贴个KMP模板吧~~~ #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; const int MAX_N = 1000008; const int MAX_M = 10008; int T[MAX_N]; int p[MAX_M]; int f[MAX_M]; int

poj 3461 Oulipo(KMP模板题)

题目链接:http://poj.org/problem?id=3461 Oulipo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 23559   Accepted: 9437 Description The French author Georges Perec (1936–1982) once wrote a book, La disparition, without the letter 'e'. He was a

剪花布条---hdu2087(kmp模板)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 kmp模板题: #include <cstdio> #include <cstring> #include <iostream> using namespace std; #define N 1100 char s1[N], s2[N]; int p[N], L1, L2; void Getp() { int i=0, j=-1; p[0] = -1; while(i

hdu 1686 KMP模板

1 // hdu 1686 KMP模板 2 3 // 没啥好说的,KMP裸题,这里是MP模板 4 5 #include <cstdio> 6 #include <iostream> 7 #include <cstring> 8 #include <algorithm> 9 10 using namespace std; 11 12 const int MAX_N = 1000008; 13 const int MAX_M = 10008; 14 char T

数据结构实验之串三:KMP应用(KMP模板)

数据结构实验之串三:KMP应用(KMP模板) AC_Code: 1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <cmath> 5 #include <map> 6 #include <stack> 7 using namespace std; 8 typedef long long ll; 9 int Nex[1000000]; 10

扩展KMP模板

扩展KMP:    给出模板串A和子串B,长度分别为lenA和lenB,要求在线性时间内,对于每个A[i](0 <= i < lenA),求出A[i..lenA-1]与B的最长公共前缀长度,记为ex[i](或者说,ex[i]为满足A[i..i + z - 1]==B[0 .. z - 1]的最大的z值).    扩展KMP可以用来解决很多字符串问题,如求一个字符串的最长回文子串和最长重复子串.[算法]    设next[i]为满足B[i..i + z - 1] == B[0..z - 1]的最

hdu 2087 剪花布条 kmp模板题

也是kuangbin专题的 专题名字太长 不复制了…… 刚好数据结构也学了kmp 找一道题敲敲模板…… 暴力的字符串匹配是O(n*m)的时间复杂度 而kmp通过一个O(m)的预处理将字符串匹配的时间复杂度降到了O(n+m) kmp的核心是next数组的处理和利用next数组进行字符串匹配 这两个理解了就会用kmp了 1 /* *********************************************** 2 Author :Sun Yuefeng 3 Created Time :