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;
}

嗯,真香

最新文章

  1. Android开发学习—— shape标签的使用
  2. Linux(Centos)之安装tomcat并且部署Java Web项目
  3. MySQL数据库优化的八种方式(经典必看)
  4. JDBC成绩管理系统
  5. Mtk Ft6306 touch 驱动 .
  6. 关于actionscript中新建一个sprite,设置大小(宽高)的问题。
  7. Selenium - IWebDriver.SwitchTo() frame 和 Window 的用法
  8. Hive(七):HQL DML
  9. ASP.NET MVC4学习笔记之总体概述
  10. hibernate导入大量数据时,为了避免内存中产生大量对象,在编码时注意什么,如何去除?
  11. KEIL C51高级编程
  12. Sublime Text3 插件安装教程
  13. junit测试时,出现java.lang.IllegalStateException: Failed to load ApplicationContext
  14. mysql GROUP_CONCAT获取分组的前几名
  15. Yii2中后台用前台的代码设置验证码显示不出来?
  16. 已操作文件的方式,新建一个用户alex
  17. Java的SSH框架整合
  18. iOS模拟器:Undefined symbols for architecture x86_64
  19. poj 3352 Road Construction(边双连通分量+缩点)
  20. 基础001_Xilinx V7资源

热门文章

  1. Spring之JdbcTemplate使用
  2. .NET Core技术研究系列-索引篇
  3. 一文带你快速搞懂动态字符串SDS,面试不再懵逼
  4. Copy-on-write + Proxy = ?
  5. PAT 1038 Recover the Smallest Number (30分) string巧排序
  6. CSS sprites的定义及使用
  7. rust 神奇的特质
  8. 记录工作中遇到的BUG,经典的数据库时区问题和字段类型tinyint(1)问题
  9. SLAM数据集序列图片如何批量处理
  10. Andrew Ng - 深度学习工程师 - Part 1. 神经网络和深度学习(Week 2. 神经网络基础)