模式匹配之KMP
来源:互联网 发布:广播电视网络宽带 编辑:程序博客网 时间:2024/05/16 04:15
注:模式串指我们要找是不是出现的串,主串指我们匹配的对象。
简介:
一种由Knuth(D.E.Knuth)、Morris(J.H.Morris)和Pratt(V.R.Pratt)三人设计的线性时间字符串匹配算法。
大致原理:
其实就是利用已经匹配过的字符,也就是在中间的每一个位置,就断开了。利用前面的部分去设置,下次寻找的点。
普通的就是这个失败,就返回刚开始的位置的下一个。继续寻找。不断的,不断的。。。
KMP的话,就是看你找过且对的上的部分的规律,通过这个规律,我们判断下一次找的点的位置,从模式串里面的那个位置开始。
比如下面的一个例子:
00000001001当1不匹配的时候,我们是返回第二个位置这样呢?(当然KMP也是这样的,但是下面的我们指只要匹配不成功,就下面一个位置继续,重新开始的那种普通匹配。)
0000001 001
以上的理由,为什么呢?这个为什么就是KMP的学习之处?还是这样?(下面的我们指直接将模式串移过来。进行判断。)
他通过判断制定一个next的规则,进行模式串下一次的位置判断点。就可以直接判断。从而实现O(n+m)的时间复杂度。
重点:每一个next的值,都是表示前看,后看的最长公共长度。
就几个例子,解释一下。好吧。
abcdefg这个例子:next为-1 -1 -1 -1 -1 -1 -1;
表示的就是最长长度为0.
如果是abcdefga呢?next就是-1 -1 -1 -1 -1 -1 -1 0了。
为什么最后是个0了呢?
哦~,原因在abcdefga这个里面前面a,后面a,所以长度就是1了。
因为初始值为-1,所以-1的就是0,0的就是1,以此类推。。。。。。
当我们知道这些next,又有什么用呢?
试想一下?
Abcabdbc这个这个主串如果你匹配到了第二个a的时候出错了。也就是你前面也有abc这三个字符的时候,你觉得你还想要去和第一个b比较吗?
明显浪费时间啊。我们明明可以去和第二个c后面的比较啊。不然至少我们也应该和第二个a比较吧。
也就是这样
虽然abc只有三个字符,但是如果相同字符达到一万个呢?你还会不会小看这点时间?这就是next的作用。
abcabcdbc abcdbc之后的寻找,其实就是普通的找了,不过加了一个next的作用而已。
也就实现了时间复杂度的缩小的作用了。
代码版署:
要想重复的搜索,有多少个只需要,找到之后让k = -1,或者0.重新找。
下面的是我的一个朋友的代码,从-1开始的next代码!
#include <cstdio>#include <iostream>#include <algorithm>#include <vector>#include <set>#include <map>#include <string>#include <stack>#include <queue>#include <cstring>using namespace std;#define REP(I,N) for (I=0;I<N;I++)#define rREP(I,N) for (I=N-1;I>=0;I--)#define rep(I,S,N) for (I=S;I<N;I++)#define rrep(I,S,N) for (I=N-1;I>=S;I--)#define FOR(I,S,N) for (I=S;I<=N;I++)typedef unsigned long long ULL;typedef long long LL;const int INF=0x3f3f3f3f;const LL INFF=0x3f3f3f3f3f3f3f3fll;const LL M=500+7;const LL N=500+7;const double eps=0.00000001;LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}template<typename T>inline T abs(T a,T b) {return a>0?a:-a;}LL n,m;char s[M],a[N];LL Next[N];LL i,j,k,t;void init(char *a,LL *Next){ Next[0]=-1; int len=strlen(a); register int i,j; FOR(i,1,len-1){ j=Next[i-1]; while (j>=0&&a[j+1]!=a[i]) j=Next[j]; if (a[i]==a[j+1]) Next[i]=j+1; else Next[i] = -1; }}int kmp(char *s,char *a,LL *Next){ int Len=strlen(s),len=strlen(a); register int i,j=-1; REP(i,Len){ while (j>=0&&a[j+1]!=s[i]) j=Next[j]; if (s[i]==a[j+1]) j++; if (j==len-1) return i-len+1; } return -1;}int main(){while (~scanf("%s%s",&s,&a)){ init(a,Next); n=strlen(a); REP(i,n) printf("%d ",Next[i]); t=kmp(s,a,Next); if (~t) printf("%d",t+1); else printf("Not Found!"); puts("");}}
之后的代码,是学校的以0为开头的KMP算法,有可能看不懂,不过没关系,看得懂前面的就可以了。(next[i],表示的是0到i-1的位置的相同长度!)
#include <iostream>#include <stdio.h>#include <string.h>#include <math.h>#include <algorithm>#include <map>#include <set>using namespace std;void get_next(char *str,int len,int *next){ next[0] = 0; next[1] = 1; int k = 0; for(int i=2; i<len; i++) { k = next[i-1]; while(k>1 && str[i-1]!=str[k-1]) k = next[k]; if(str[i-1] == str[k-1]) next[i] = k+1; else next[i] = 1; }}void print_next(int *next,int len){ for(int i=0; i<len; i++) printf("%d ",next[i]); printf("\n");}int KMP(char *str,int slen,char *vision,int len,int *next){ int j = 0; for(int i=0; i<slen; i++) { while(j>0 && str[i] != vision[j]) j = next[j]-1; if(str[i] == vision[j]) j++; if(j==len) return i-len+1; } return -1;}int main(){ char str[100],vision[100]; int slen,len,next[100]; while(scanf("%s%s",&str,&vision)!=EOF) { len = strlen(vision); slen = strlen(str); get_next(vision,len,next); print_next(next,len); printf("%d\n",KMP(str,slen,vision,len,next)); } return 0;}
代码版署,也就结束了。学校的测试过了。不过我希望博友们,可以留言,指正一下可能的错误点或者测试用例。
最后留言:
谢谢,各位大佬!(如果人生有3600秒,那么我只想说你现在属于我!哈哈)
- KMP之模式匹配
- 模式匹配之KMP
- 数据结构之kmp模式匹配
- 串模式匹配之------KMP
- 【算法】模式匹配之KMP
- 模式匹配之KMP算法
- 模式匹配之KMP算法
- 转载数据结构之kmp模式匹配
- 模式匹配之Kmp/BM专题
- 数据结构 字符串模式匹配之KMP算法
- 算法:模式匹配之KMP算法
- 模式匹配之(BF KMP算法)
- 模式串匹配之KMP算法详解
- 模式匹配---KMP算法
- kmp 模式匹配。。。。
- 模式匹配 KMP算法
- 模式匹配-KMP算法
- KMP模式匹配算法
- win7旗舰版关闭自动更新
- 进程和task_struct
- SQL语言分类DDL、DML、DQL、TCL、DCL
- NetWork局域网组件
- PopupWindow自定义对话框的使用技巧
- 模式匹配之KMP
- codeforces 8a(string的操作)
- JAVA中的栈和堆
- 利用腾讯AI开放平台进行情感分析
- 【C++11】新特性——引入nullprt
- [后端人员耍前端系列]KnockoutJs篇:使用KnockoutJs+Bootstrap实现分页
- Sublime Text3 注册码
- spring--目录
- unity3d 混合树