浅谈KMP算法——Chemist
很久以前就学过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的更多相关文章
- 浅谈KMP算法及其next[]数组
KMP算法是众多优秀的模式串匹配算法中较早诞生的一个,也是相对最为人所知的一个. 算法实现简单,运行效率高,时间复杂度为O(n+m)(n和m分别为目标串和模式串的长度) 当字符串长度和字符集大小的比值 ...
- 单模式串匹配----浅谈kmp算法
模式串匹配,顾名思义,就是看一个串是否在另一个串中出现,出现了几次,在哪个位置出现: p.s. 模式串是前者,并且,我们称后一个 (也就是被匹配的串)为文本串: 在这篇博客的代码里,s1均为文本串, ...
- 浅谈KMP算法
一.介绍 烤馍片KMP算法是用来处理字符串匹配问题的.比如说给你两个字符串A,B,问B是不是A的子串? 比如,eg就是aeggx的子串 一般讲字符串A称为主串,用来匹配的B串称为模式串 定义n为字符串 ...
- 【字符串算法3】浅谈KMP算法
[字符串算法1] 字符串Hash(优雅的暴力) [字符串算法2]Manacher算法 [字符串算法3]KMP算法 这里将讲述 [字符串算法3]KMP算法 Part1 理解KMP的精髓和思想 其实KM ...
- 【文文殿下】浅谈KMP算法next数组与循环节的关系
KMP算法 KMP算法是一种字符串匹配算法,他可以在O(n+m)的时间内求出一个模式串在另一个模式串下出现的次数. KMP算法是利用next数组进行自匹配,然后来进行匹配的. Next数组 Next数 ...
- 浅谈 KMP 算法
最近在复习数据结构,学到了 KMP 算法这一章,似乎又迷糊了,记得第一次学习这个算法时,老师在课堂上讲得唾沫横飞,十分有激情,而我们在下面听得一脸懵比,啥?这是个啥算法?啥玩意?再去看看书,完全听不懂 ...
- 浅谈分词算法(5)基于字的分词方法(bi-LSTM)
目录 前言 目录 循环神经网络 基于LSTM的分词 Embedding 数据预处理 模型 如何添加用户词典 前言 很早便规划的浅谈分词算法,总共分为了五个部分,想聊聊自己在各种场景中使用到的分词方法做 ...
- 浅谈分词算法(4)基于字的分词方法(CRF)
目录 前言 目录 条件随机场(conditional random field CRF) 核心点 线性链条件随机场 简化形式 CRF分词 CRF VS HMM 代码实现 训练代码 实验结果 参考文献 ...
- 浅谈分词算法(3)基于字的分词方法(HMM)
目录 前言 目录 隐马尔可夫模型(Hidden Markov Model,HMM) HMM分词 两个假设 Viterbi算法 代码实现 实现效果 完整代码 参考文献 前言 在浅谈分词算法(1)分词中的 ...
随机推荐
- 最长上升子序列(LIS)长度的O(nlogn)算法
最长上升子序列(LIS)的典型变形,熟悉的n^2的动归会超时.LIS问题可以优化为nlogn的算法.定义d[k]:长度为k的上升子序列的最末元素,若有多个长度为k的上升子序列,则记录最小的那个最末元素 ...
- Spring mvc之SimpleUrlHandlerMapping
1.配置文件如下 <bean id="method" class="com.xx.controller.xxxController" scope=&quo ...
- 多线程调用COM组件的体会(CoInitialize)
调用任何COM组件之前,你必须首先初始化COM套件环境,即调用CoInitialize或CoInitializeEx.COM套件环境在线程的生存周期内有效,线程退出前需要调用CoUninitializ ...
- Python访问MySQL数据库并实现其增删改查功能
概述:对于访问MySQL数据库的操作,我想大家也都有一些了解.不过,因为最近在学习Python,以下就用Python来实现它.其中包括创建数据库和数据表.插入记录.删除记录.修改记录数据.查询数据.删 ...
- storm的例子,一个非常好的网址
https://insight.io/github.com/apache/storm/tree/HEAD/examples/storm-elasticsearch-examples/src/main/ ...
- linux 下的特殊文件 /dev/null 和 /de/zero
生成一个100Mb的文件 : time dd of=2Gb.file if=/dev/zero bs=1024 count=100000 ubuntu 下测试磁盘的读写性能: 测试写: time d ...
- string 是值类型,还是引用类型(.net)[转]
转自http://hi.baidu.com/newfzks/item/b805f0f4edb0810dd89e7290 string 是值类型,还是引用类型(.net) 一. string 类型的用法 ...
- OpenCV实践之路——Python的安装和使用
本文由@星沉阁冰不语出品,转载请注明作者和出处. 文章链接:http://blog.csdn.net/xingchenbingbuyu/article/details/50936076 微博:http ...
- python各进制、字节串间的转换
>>> i = 13 >>> bin(i) '0b1101' >>> oct(i) '0o15' >>> hex(i) '0xd ...
- HTML5开发实战——Sencha Touch篇(1)
学习了很多主要的Sencha Touch内容,已经了解了Sencha Touch的开发模式.接下来一段时间我们将利用Sencha Touch来进行自己的web应用构建. 先要解决的是前端的问题.从最简 ...