First.先上一份最原始的无任何优化的代码(暴力):

#include <iostream>
#include <cstring>
using namespace std;
char s[1000],p[1000]; inline int getans(char* s,char* p){
int sl=strlen(s),pl=strlen(p);
int i=0,j=0;
while(i<sl && j<pl){
if(s[i]==p[j])
i++,j++;
else{
i=i-j+1;
j=0;
}
}
if(j==pl) return i-j;
else return -1;
} int main(){
cin>>s>>p;
int ans=getans(s,p);
cout<<ans<<endl;
return 0;
}

对于文本串S和模拟串P,进行匹配。

i表示S串的位置,同理,j表示P串的位置;

若当前字符匹配,则进行下一个(i++,j++);

否则,将P归零,S回溯到上一次匹配的位置;

输出的是第一次匹配的位置。

Second.开始第一次优化(KMP):

在上述的暴力中,我们可以发现,每次失配时,i返回到了前面很远的地方,所以我们想搞这样一个东西;

它具备一个特殊性质:

在每次失配是,直接让P跳到这个位子上,大大减少复杂度。

在此,我们需要引入一个叫做next的数组;

但是,仍然有最坏的情况,就是需要重新匹配;

那么此时的next[i]=0或-1,表示重头在来;

若next[i]=k,则表示P跳过了k个字符。

简略代码:

inline int KMPsearch(char* s,char* p){
int sl=strlen(s),pl=strlen(p);
int i=0,j=0;
while(i<sl && j<pl){
if(s[i]==p[j]||j==-1)//j==-1表示匹配成功,进行后续的字符匹配
i++,j++;
else
j=nxt[j];//i不用变,j直接跳到预处理好的next[j]处
}
if(j==pl) return i-j;
else return -1;
}

1.

next数组记录的是长度最大且相等的前缀后缀;

举个例子:

P1:   ABA

P2:   ABAB

在P1中,他有长度为1的相同前缀后缀A

在P2中,他有长度为2的相同前缀后缀AB

(盗图勿喷)

2.

我们来求next数组;

将第一步中的长度稍作变形即可;

(同上)

整体右移一位,将第一位赋值为-1。

也可以这样理解:(与-1无关了就)

如果相等,则该位的next值就是前一位的next值加上1;

如果不等,向前继续寻找next值对应的内容来与前一位进行比较,直到找到某个位上内容的next值对应的内容与前一位相等为止,则这个位对应的值加上1即为需求的next值;如果找到第一位都没有找到与前一位相等的内容,那么需求的位上的next值即为1。

3.

代码求next数组;

inline void GetNext2(char *p,int nxt[]){
int pl=strlen(p);
nxt[0]=-1;
int k=-1;
int j=0;
while(j<pl-1){
if(k==-1 || p[j]==p[k]){
++j,++k;
if(p[j]!=p[k])
nxt[j]=k;
else nxt[j]=nxt[k];
}
else k=nxt[k];
}
}

Third.对于next数组的优化:

在上文所述中,有个小问题:

就是说,在j向后跳到了next[k]时,必然失配,

就是因为p[j]=p[next[j]];

那就要处理出所有这种情况,递归

next[j]=p[next[next[j]]]。

Finally.整体代码(可直接食用哦):

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std; char s[100],p[100];
int nxt[100]; inline void GetNext2(char *p,int nxt[]){
int pl=strlen(p);
nxt[0]=-1;
int k=-1;
int j=0;
while(j<pl-1){
if(k==-1 || p[j]==p[k]){
++j,++k;
if(p[j]!=p[k])
nxt[j]=k;
else nxt[j]=nxt[k];
}
else k=nxt[k];
}
} inline int KMPsearch(char* s,char* p){
int sl=strlen(s),pl=strlen(p);
int i=0,j=0;
while(i<sl && j<pl){
if(s[i]==p[j]||j==-1)
i++,j++;
else
j=nxt[j];
}
if(j==pl) return i-j;
else return -1;
} int main(){
cin>>s>>p;
GetNext2(p,nxt);
int ans=KMPsearch(s,p);
cout<<ans<<'\n';
return 0;
}

嗯,真香

KMP入门的更多相关文章

  1. zstu.4194: 字符串匹配(kmp入门题&& 心得)

    4194: 字符串匹配 Time Limit: 1 Sec  Memory Limit: 128 MB Submit: 206  Solved: 78 Description 给你两个字符串A,B,请 ...

  2. 题解报告:hdu 2087 剪花布条(KMP入门)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2087 Problem Description 一块花布条,里面有些图案,另有一块直接可用的小饰条,里面 ...

  3. hdu 1358 Period(KMP入门题)

    Period Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Total Subm ...

  4. KMP入门题目[不定期更新]

    HDU 1711 Number Sequence(模板题) #include <cstdio> ; ; int N, M; int textS[MAXN]; int tarS[MAXL]; ...

  5. KMP入门(匹配)

    Description Given two sequences of numbers : a[1], a[2], ...... , a[N], and b[1], b[2], ...... , b[M ...

  6. hdu 1358 period KMP入门

    Period 题意:一个长为N (2 <= N <= 1 000 000) 的字符串,问前缀串长度为k(k > 1)是否是一个周期串,即k = A...A;若是则按k从小到大的顺序输 ...

  7. hdu 1686 & poj 2406 & poj 2752 (KMP入门三弹连发)

    首先第一题 戳我穿越;http://acm.hdu.edu.cn/showproblem.php?pid=1686 题目大意好理解,每组输入一个子串和一个母串,问在母串中有多少个子串? 文明人不要暴力 ...

  8. HDU2203(KMP入门题)

    亲和串 Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submiss ...

  9. HDU2087(KMP入门题)

    剪花布条 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  10. HUD1686(KMP入门题)

    Oulipo Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

随机推荐

  1. surface go重新做系统

    此教程适用于使用U盘恢复介质来恢复Surface Go二合一设备系统SurfaceGo_BMR_45_64_1.011.2.zip 大致两个步骤 一.制作U盘恢复介质 下载适用于自己平板的恢复镜像文件 ...

  2. 我们为什么要用hibernate

    1.hibernate对JDBC访问数据库的代码做了一个封装,简化了数据访问繁琐的代码. 2.hibernate的性能非常好,因为它是个轻量级框架.映射的灵活性很好,它支持各种关系型数据库,从一对一到 ...

  3. ubuntu12.04 empathy添加qq登陆

    1,

  4. 「雅礼集训 2017 Day4」洗衣服

    题目   点这里看题目. 分析   首先考虑只有洗衣机的情况.我们可以想到,当前洗衣任务结束越早的洗衣机应该被先用,因此可以用堆来动态维护.   再考虑有烘干机的情况.很显然,越晚洗完的衣服应该越早烘 ...

  5. 【01JMeter基础】线程组

    线程组 我们存在接口请求的地方,在JMeter中我们使用最多的模块,分为 setUp线程组.线程组.tearDown线程组 setUp线程组:不论如何排序,都会在所有的线程组中被最早执行,如果有多个s ...

  6. 前后端分离项目 nginx配置实践

    新项目采用前后端分离的方式开发,前后端代码打算分开部署(同机器且同域名),但打算支持后端依然可访问静态资源. 搜索nginx配置大部分都通过url前缀进行转发来做前后端分离,不适用目前项目. 说明 前 ...

  7. rust 宏

    macro_rules! four { () => {1 + 3}; } fn main(){ println!("{}", 1+four!()); println!(&qu ...

  8. mysql大表在不停机的情况下增加字段该怎么处理

    MySQL中给一张千万甚至更大量级的表添加字段一直是比较头疼的问题,遇到此情况通常该如果处理?本文通过常见的三种场景进行案例说明. 1. 环境准备 数据库版本: 5.7.25-28(Percona 分 ...

  9. vue 入门, todoList

    #  实现逻辑: > * 技术栈> 1. 生命周期,creatd( 创建后执行)> 2. methods': 调用事件方法,结果不会缓存> 3. Watch : 监听器,监听输 ...

  10. weblogic高级进阶之查看日志

    域的日志位于 D:\Oracle\Middleware\user_projects\domains\base_domain\servers\AdminServer\logs 名字是base_domai ...