▎前言

  这次要讲的HMP算法KMP算法很简单,是用于处理字符串的,之前一直以为很难,其实也不过如此(说白了就是优化一下暴力)。

▎处理的问题

  通常处理的问题是这样的:给定两个字符串s1和s2,其中s1是文本串,s2是匹配串,求s2在s1中出现的位置。

  举个例子:(方便起见,下标从1开始)比如说s1是AABAAC,s2是BA,那么s2在s1的第3个位置处出现。

▎暴力求解

  如何使用暴力求解这道题呢?我们只要分别暴力遍历两个字符串,然后分别比对当前字符,如果相等就继续比下去,如果不相等,那么s1回溯回没有执行这一次比对的位置,s2遍历的位置归零。

  代码如下,详见注释:

 #include<iostream>
using namespace std;
string s1,s2;int i=,j=;
int main()
{
cin>>s1;cin>>s2;
int len1=s1.length();int len2=s2.length();
while(i<len1&&j<len2)
{
if(s1[i]==s2[j])
{
i++;
j++;
}
else
{
i=i-j+;
j=;
}
}
if(j==len2) cout<<i-j;
else cout<<"No answer";
return ;
}

▎KMP算法

☞『定义』

  KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特莫里斯普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n)。(copy自百度)

  说白了就是把暴力求解的过程优化一下。

☞『算法核心』

  仔细思考一下,为什么暴力求解效率不高呢?

  这个问题很好回答,因为我们直接比对失败后就抛弃了,因此没有利用到这些匹配失败的东西,如果我们能够合理的利用,在失败的基础上继续比对,那么就可以优化了。

  KMP算法不同于暴力的地方就在于把比对失败的当前遍历的字符串准确找到一个之前信息一样的字符串,继续比对。  

  比如说s1是AABAAC,s2是AB,在遍历到AA时发现不同,那么之前相同的是A,那么跳转到下一个A所在的位置继续比对,也就是跳到了第二个A的位置,发现相同,那么就找到了。

  其余的与暴力相同,只不过跳转就成为了一大难点。

  那么我们现在来考虑如何跳转,我们可以使用一个数组(next)来存储当前信息相同的位置,那么我们可以定义两个指针(不是语法中的指针,此指针非彼指针),初始化一个在0,一个在-1。

  如果一个在-1(还没有开始比对,或者跳转到了这里)或者当前字符相同,那么就继续比对。否则就将其中一个跳转。

  总而言之看代码吧。

☞『代码如下』

 #include<iostream>
#include<cstring>
using namespace std;
char s1[],s2[];int i=-,j=,next[];
int main()
{
cin>>s1;cin>>s2;
int len1=strlen(s1);int len2=strlen(s2);//输入字符串
next[]=-;//初始化
while(j<len2-)
{
if(i==-||s2[i]==s2[j])//-1可能是初始状态的,也可能是跳过来的
{
i++;
j++;
next[j]=i;//顺便记录下来
}
else i=next[i];//跳到另一个信息一样的地方
}
i=;j=;
while(i<len1&&j<len2)//常规操作
{
if(j==-||s1[i]==s2[j])
{
i++;
j++;
}
else j=next[j];//跳转
}
if(j==len2) cout<<i-j;
else cout<<"No answer";
return ;
}

【算法•日更•第三十一期】KMP算法的更多相关文章

  1. 【算法•日更•第三十期】区间动态规划:洛谷P4170 [CQOI2007]涂色题解

    废话不多说,直接上题:  P4170 [CQOI2007]涂色 题目描述 假设你有一条长度为5的木版,初始时没有涂过任何颜色.你希望把它的5个单位长度分别涂上红.绿.蓝.绿.红色,用一个长度为5的字符 ...

  2. 【算法•日更•第三十九期】迭代加深搜索:洛谷SP7579 YOKOF - Power Calculus 题解

    废话不多说,直接上题: SP7579 YOKOF - Power Calculus 题意翻译 (略过没有营养的题干) 题目大意: 给出正整数n,若只能使用乘法或除法,输出使x经过运算(自己乘或除自己, ...

  3. 【算法•日更•第三十五期】FF算法优化:EK算法

    ▎写在前面 FF算法传送门 之前我们已经学过了FF算法(全称Ford-Fulkerson算法)来找最大流,但是这种算法仍有诸多不对的地方. 其实这种算法存在着严重的效率的问题,请看下面的图: 以这个图 ...

  4. 【算法•日更•第三十二期】教你用出windows体验的Linux

    ▎前言 小编昨天闲的不行,就装了一个linux系统,linux的发行版很多,小编认为ubuntu很好用,于是就在使用ubuntu. 没错,我现在就在使用ubuntu来写博客. 刚才还装了一个QQ,不过 ...

  5. 【算法•日更•第五十期】二分图(km算法)

    ▎前言 戳开这个链接看看,惊不惊喜,意不意外?传送门. 没想到我的博客竟然被别人据为己有了,还没办法投诉. 这年头写个博客太难了~~~ 之前小编写过了二分图的一些基础知识和匈牙利算法,今天来讲一讲km ...

  6. 【算法•日更•第五十四期】知识扫盲:什么是operator?

    ▎前言 这个东西和迭代器长的很像,但是比迭代器常见的多. 今天就来浅谈operator. ▎定义 operator是C#.C++和pascal的关键字,它和运算符一起使用,表示一个运算符函数,理解时应 ...

  7. 【算法•日更•第三十七期】A*寻路算法

    ▎写在前面 这是一种搜索算法,小编以前总是念成A乘寻路算法,没想到一直念错. 请大家都念成A星寻路算法,不要像小编一样丢人了. ▎A*寻路算法 ☞『引入』 相信大家都或多或少的玩过一些游戏吧,那么游戏 ...

  8. 【算法•日更•第四十二期】离散傅里叶变换(DFT)

    ▎前言 小编相当的菜,这篇博客难度稍高,所以有些可能不会带有证明,博客中更多的是定义. 我们将要学到的东西: 复数 暴力多项式乘法 DFT 当然,小编之前就已经写过一篇博客了,主要讲的就是基础多项式, ...

  9. 【算法•日更•第四十三期】QQ for linux

    废话不多说,直接看一张图: 没错,这是QQ,但是这有什么稀奇的?但是在Linux上使用QQ就很稀奇了. 众所周知,腾讯早就已经对Linux下的QQ和微信停止了服务,即便是网页版也不能用,通信这一直是小 ...

随机推荐

  1. DJANGO-天天生鲜项目从0到1-013-订单-支付宝支付

    本项目基于B站UP主‘神奇的老黄’的教学视频‘天天生鲜Django项目’,视频讲的非常好,推荐新手观看学习 https://www.bilibili.com/video/BV1vt41147K8?p= ...

  2. 网络流(EK算法)

    poj1273 #include <iostream> #include <cstdio> #include <cstring> #include <queu ...

  3. element ui表格实现单选 但是单选取消会报错

    1.在el-table中添加两个事件  @selection-change="handleSelectionChange"  @current-change="choos ...

  4. Pexpect模块的简单使用

    Pexpect 是一个用来启动子程序并对其进行自动控制的 Python 模块. Pexpect 可以用来和像 ssh.ftp.passwd.telnet 等命令行程序进行自动交互.以下所有代码都是在K ...

  5. Tomcat Script(python)

    由于刚接触 Python,所以使用Python 书写一些小的脚本,进行备忘同时分享给大家 #!/usr/bin/env python # _*_coding:utf-8_*_ # author: 'l ...

  6. Java容器学习之List

    List接口继承了Collcetion接口,Collection接口又继承了超级接口Iterable,List是有序列表,实现类有ArrayList.LinkedList.Vector.Stack等. ...

  7. Jenkins部署jmx脚本

      针对jenkins+jmeter做接口自动化,jmeter完成测试脚本录入和撰写,而jenkins负责持续集成和报告收集.那么从零实现jenkins可以从以下角度实现 首先需要安装jenkins ...

  8. activiti7 导出bpmn文件

    最近在学习springboot+activiti7整合,想做一个导出bpmn文件的功能,查了相关资料,最后没有实现.最后查看了一下代码 找到了方法 如下所示 @GetMapping("exp ...

  9. SpringBoot动态注入Bean

    目的: 在程序运行期间,动态添加Bean进入到Spring容器. 目前使用到的场景: 对当当网的ElasticJob进行封装,通过自定义注解@ElasticJob的方式开启分布式定时任务. 当所有的B ...

  10. Python os.write() 方法

    write()方法语法格式如下:高佣联盟 www.cgewang.com os.write(fd, str) 参数 fd -- 文件描述符. str -- 写入的字符串. 返回值 该方法返回写入的实际 ...