很久以前就学过KMP,不过一直没有深入理解只是背代码,今天总结一下KMP算法来加深印象。

一、KMP算法介绍

  • KMP解决的问题:给你两个字符串A和B(|A|=n,|B|=m,n>m),询问一个字符串在另一个字符串中的每一次出现位置。
  • 暴力:枚举长串中的每一个起点,然后一位一位判断是否与短串完全相同,枚举复杂度是O(n),比较的复杂度是O(m),总的时间复杂度是O(nm),时间复杂度比较差
  • 引入两个定义:

1.匹配串(A):被匹配的长串。

2.模式串(B):在匹配串中每次找出现位置的短串。

  • 在匹配的过程中,我们相当于是要每次找到匹配串的一个前缀的后缀与模式串的一个前缀完全相同,也就是说,我们需要在匹配串上维护一个指针i,在模式串上维护一个指针j,使得Ai-j+1~i = B1~j 。

  举个例子:匹配串为abbabab,模式串为abbaa,当A[i]==B[j]时直接往后继续找,当i=5,j=5时会产生失配,这时按照我们暴力的想法,我们会将i退回的到2位置,将j退回到1的位置,然后重复此过程,然而我们考虑一下就会发现这一段是一个字符也匹配不上的,因为A1~5已经和B1~5匹配上了,如果A2~6可以和B1~5匹配,则说明A1~5与A2~6完全相同,然而显然不同,于是我们有了新的思路,当我们失配时,我们缩小j,直到A的以i为结尾的前缀的后缀与B的长度为j的前缀完全相同,也就是说找到一个最大的k使得Ai-k+1~i=B1~j(k<j)。那么如何快速找到k呢?

  • 这里我们引入next数组,next[j]表示模式串中长度为j-1的前缀中最长的前缀等于后缀的长度,那么当A[i]与B[j]失配时j需要往前移j-next[j]位,显然next[1]=0。
  • 如何求出next数组?自己与自己匹配,如果可以匹配上,即Bnext[j-1]+1=Bj,那么next[j]=next[j-1]+1,如果不能匹配上,就让next往回跳直到可以匹配。(如果不理解可以自行画图模拟,很容易就可以理解。)
  • KMP算法的大致思路就介绍完了,就是先让模式串自己与自己匹配求出next数组,然后用next数组辅助与匹配串匹配。时间复杂度为O(N+M)。

代码(洛谷P3375):

#include<bits/stdc++.h>
using namespace std;
const int MAXX=1e6+;
char s1[MAXX],s2[MAXX];
int l1,l2,next[MAXX];
//next[i]表示s2中以i为结尾的非前缀子串与A的前缀能够匹配的最大长度
void KMP()
{
for(int i=,j=;i<l2;i++){
while(j&&s2[i]!=s2[j])
j=next[j];//匹配不到就往下找
if(s2[i]==s2[j])j++;
next[i+]=j;
}
for(int i=,j=;i<l1;i++){
while(j&&s1[i]!=s2[j])j=next[j];
if(s1[i]==s2[j])j++;
if(j==l2){
//找到一次出现
printf("%d\n",i-l2+);
}
}
}
int main()
{
cin>>s1;cin>>s2;
l1=strlen(s1);l2=strlen(s2);
KMP();
for(int i=;i<=l2;i++)
printf("%d ",next[i]);
return ;
}

二、KMP小应用

  • 1.(口胡题意)给你一个长度为n的字符串S,求它的最小循环节,n<=100000。

  x是S的循环节的等价条件是S1~n-x+1=Sx+1~n,最小化x相当于最大化n-x+1,也就是求出next[n],然后n-next[n]几位答案。代码略。

  • 2.CF126B Password(https://www.luogu.org/problemnew/show/CF126B)

  一句话题意:给你一个字符串S(|S|<=1000000),找到既是S前缀又是S后缀又在S中间出现过(既不是S前缀又不是S后缀)的最长子串。

  既是前缀又是后缀的最长子串很容易找,直接用上面的KMP求出next数组,next[n]即为答案,而中间出现过的子串就相当于一个前缀的后缀,所以我们只需找到不等于n的next[i]中最大的i,然后让next[n]不断往前跳直到他的长度小于前面的最大长度,这是找到这个位置往后的长度个字符构成的字符串就是答案,如果在寻找的过程中next[n]跳到0还没有找到说明无解。

代码:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
char a[];
int next[],n,maxx=;
void cal()//求出next数组
{
next[]=;
for(int i=,j=;i<=n;i++){
while(j&&a[i]!=a[j+])j=next[j];
if(a[i]==a[j+])j++;
next[i]=j;
if(i!=n)maxx=max(next[i],maxx);
//找到next数组的最大值
}
}
int main()
{
cin>>a+;
n=strlen(a+);
cal();
int x=next[n];
if(x==)printf("Just a legend\n");
else{
while(x>maxx)x=next[x];
//找到小于max{next[1~n-1]}的最大匹配长度
if(x==){
printf("Just a legend\n");
return ;
}
for(int i=;i<n;i++)
if(x==next[i]){
for(int j=i-next[i]+;j<=i;j++)
//i-next[i]+1为答案子串的左端点
printf("%c",a[j]);
printf("\n");
return ;
}
}
return ;
}

浅谈KMP算法——Chemist的更多相关文章

  1. 浅谈KMP算法及其next[]数组

    KMP算法是众多优秀的模式串匹配算法中较早诞生的一个,也是相对最为人所知的一个. 算法实现简单,运行效率高,时间复杂度为O(n+m)(n和m分别为目标串和模式串的长度) 当字符串长度和字符集大小的比值 ...

  2. 单模式串匹配----浅谈kmp算法

    模式串匹配,顾名思义,就是看一个串是否在另一个串中出现,出现了几次,在哪个位置出现: p.s.  模式串是前者,并且,我们称后一个 (也就是被匹配的串)为文本串: 在这篇博客的代码里,s1均为文本串, ...

  3. 浅谈KMP算法

    一.介绍 烤馍片KMP算法是用来处理字符串匹配问题的.比如说给你两个字符串A,B,问B是不是A的子串? 比如,eg就是aeggx的子串 一般讲字符串A称为主串,用来匹配的B串称为模式串 定义n为字符串 ...

  4. 【字符串算法3】浅谈KMP算法

    [字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述  [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...

  5. 【文文殿下】浅谈KMP算法next数组与循环节的关系

    KMP算法 KMP算法是一种字符串匹配算法,他可以在O(n+m)的时间内求出一个模式串在另一个模式串下出现的次数. KMP算法是利用next数组进行自匹配,然后来进行匹配的. Next数组 Next数 ...

  6. 浅谈 KMP 算法

    最近在复习数据结构,学到了 KMP 算法这一章,似乎又迷糊了,记得第一次学习这个算法时,老师在课堂上讲得唾沫横飞,十分有激情,而我们在下面听得一脸懵比,啥?这是个啥算法?啥玩意?再去看看书,完全听不懂 ...

  7. 浅谈分词算法(5)基于字的分词方法(bi-LSTM)

    目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...

  8. 浅谈分词算法(4)基于字的分词方法(CRF)

    目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...

  9. 浅谈分词算法(3)基于字的分词方法(HMM)

    目录 前言 目录 隐马尔可夫模型(Hidden Markov Model,HMM) HMM分词 两个假设 Viterbi算法 代码实现 实现效果 完整代码 参考文献 前言 在浅谈分词算法(1)分词中的 ...

随机推荐

  1. POJ 1797 【一种叫做最大生成树的很有趣的贪心】【也可以用dij的变形思想~】

    题意: 给一个无向图,找1到n所有的路中每条路最小权值的最大值! 屌丝一开始的思想是利用dij的变形~ 但是==屌丝忘记了更新dis数组~结果TLE无数次... 说正经的~dij的变形思想是这样的if ...

  2. python读取大文件的方法

    python计算文件的行数和读取某一行内容的实现方法 :最简单的办法是把文件读入一个大的列表中,然后统计列表的长度.如果文件的路径是以参数的形式filepath传递的,那么只用一行代码就可以完成我们的 ...

  3. Defcon 23最新开源工具NetRipper代码分析与利用

    0×01 研究背景 在分析了俄罗斯人被曝光的几个银行木马的源码后,发现其大多均存在通过劫持浏览器数据包来获取用户个人信息的模块,通过截获浏览器内存中加密前或解密后的数据包来得到数据包的明文数据.在De ...

  4. Android拍照、摄像方向旋转的问题 代码具体解释

    近期做了个拍照.摄像的应用.遇到了拍照.摄像的图像相对于现实.翻转了90度.原因:相机这个硬件的角度是横屏的角度,所以会出现都是横屏的. 1.照相.摄影预览图像的正确角度显 示: public sta ...

  5. Deepin-添加path

    以管理员权限添加path(Debian系列) sudo gedit /etc/profile 添加path路径格式是: export PATH=”$PATH:your path1:your path2 ...

  6. 基于Spring-SpringMVC-Mybatis的简单样例

    复习下 好久没搞过撸过代码了! 这个样例包括一个完整的增删改查! 源代码地址http://download.csdn.net/detail/wangdianyong/8909903

  7. 李洪强iOS开发之函数式 编程初窥

    函数式 编程初窥   最近在学习Erlang和Python.Erlang是完全的函数式编程语言,Python语言是面向对象的语言,但是它的语法引入了大量的函数式编程思想.越研究越觉得函数式的编程思路可 ...

  8. Android:内存控制及OOM处理

      1. OOM(内存溢出)和Memory Leak(内存泄露)有什么关系? OOM可能是因为Memory Leak,也可能是你的应用本身就比较耗内存(比如图片浏览型的).所以,出现OOM不一定是Me ...

  9. web 界面设计---大道至简

    http://www.cnblogs.com/coder2012/p/4023442.html 一个非常精简的webpy页面博客 qing.weibo.com 新浪的轻微博也不错精简

  10. 2016/04/26 流程 数据库lcdb 四个表 1,用户表users 2,流程表(设定有哪些流程)liucheng 3,流程发起者表(记录谁发起到哪里) 4,流程经过的人员表 flowpath (order排序)

    流程:      十一 个页面 1,denglu.php(登录) <!DOCTYPE html> <html lang="en"> <head> ...