母串:S[i]

模式串:T[i]

标记数组:Next[i](Next[i]表示T[0~i]最长前缀/后缀数)

先来讲一下最长前缀/后缀的概念

例如有字符串T[6]=abcabd接下来讨论的全部是真前缀/真后缀,也就是除去串自己本身之外的前缀/后缀

T[0]=a,此时前后缀都是a那么Next[0]=1

T[0~1]=ab,此时前缀为a,后缀为b两者不等因此Next[1]=0

T[0~2]=abc,此时前缀为a,ab,后缀为bc,c同上有Next[2]=0

T[0~3]=abca,此时前缀为a,ab,abc,后缀为bca,ca,a可以看到共同部分只有a因此Next[3]=1

T[0~4]=abcab,此时前缀为a,ab,abc,abca,后缀为bcab,cab,ab,b此时最长的公共部分为ab因此Next[4]=2

T[0~5]=abcabd,此时前缀为a,ab,abc,abca,abcab,后缀为bcabd,cabd,abd,bd,d无相等部分故Next[5]=0

说完前后缀的概念之后再来说说KMP的核心思想

例如S=abcabcabdabba,T=abcabd匹配时的情况如下

可以看到在S[5]的位置匹配失败,KMP的处理方式如下

说一下原因,在S[5]的位置匹配失败后直接用S[5]与T[2]去开始匹配,因为Next[5-1]也就是Next[4]=2,因此直接从T[2]重新开始匹配

原因很简单,既然Next[4]=2那么T[0~1]既可以与S[0~1]相等,也可以与S[3~4]相等,所以可以直接从T[2]开始,这也是KMP的精妙所在,不理解的可以自己写两个串试试。所以难点就在于Next数组的实现了,具体实现过程如下

这里只介绍了核心思想,原文比较详细请见:https://www.douban.com/note/321870890/

下面给出kuangbin大神的模板

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<math.h>
#include<string.h>
#include<vector>
#include<queue>
#include<iterator>
#include<vector>
#include<set>
#define dinf 0x3f3f3f3f
typedef long long ll;
//const int Max=(1<<16)+10;
using namespace std;
#define SIZE 100000005 const int N = ;
int m_next[N];
char S[N],T[N];
int slen, tlen; void getNext()
{
int j, k;
j = ; k = -; m_next[] = -;
while(j < tlen)
if(k == - || T[j] == T[k])
m_next[++j] = ++k;
else
k = m_next[k]; }
/*
返回模式串T在主串S中首次出现的位置
返回的位置是从0开始的。
*/
int KMP_Index()
{
int i = , j = ;
getNext(); while(i < slen && j < tlen)
{
if(j == - || S[i] == T[j])
{
i++; j++;
}
else
j = m_next[j];
}
if(j == tlen)
return i - tlen+;
else
return -;
}
/*
返回模式串在主串S中出现的次数
*/
int KMP_Count()
{
int ans = ;
int i, j = ; if(slen == && tlen == )
{
if(S[] == T[])
return ;
else
return ;
}
getNext();
for(i = ; i < slen; i++)
{
while(j > && S[i] != T[j])
j = m_next[j];
if(S[i] == T[j])
j++;
if(j == tlen)
{
ans++;
j = m_next[j];
}
}
return ans;
}
int main()
{ int TT;
int i, cc;
string str;
cin>>TT;
while(TT--)
{
getchar(); scanf("%s %s",&T,&S);
slen = strlen(S);
tlen = strlen(T); cout<<"模式串T在主串S中首次出现的位置是: "<<KMP_Index()/+<<endl;
cout<<"模式串T在主串S中出现的次数为: "<<KMP_Count()<<endl;
}
return ;
}

理解KMP算法的更多相关文章

  1. 理解 KMP 算法

    KMP(The Knuth-Morris-Pratt Algorithm)算法用于字符串匹配,从字符串中找出给定的子字符串.但它并不是很好理解和掌握.而理解它概念中的部分匹配表,是理解 KMP 算法的 ...

  2. 深入理解KMP算法

    前言:本人最近在看<大话数据结构>字符串模式匹配算法的内容,但是看得很迷糊,这本书中这块的内容感觉基本是严蔚敏<数据结构>的一个翻版,此书中给出的代码实现确实非常精炼,但是个人 ...

  3. KMP算法详解 --- 彻头彻尾理解KMP算法

    前言 之前对kmp算法虽然了解它的原理,即求出P0···Pi的最大相同前后缀长度k. 但是问题在于如何求出这个最大前后缀长度呢? 我觉得网上很多帖子都说的不是很清楚,总感觉没有把那层纸戳破, 后来翻看 ...

  4. 从头到尾测地理解KMP算法【转】

    本文转载自:http://blog.csdn.net/v_july_v/article/details/7041827 1. 引言 本KMP原文最初写于2年多前的2011年12月,因当时初次接触KMP ...

  5. 深入理解KMP算法之续篇

    前言: 纠结于KMP已经两天了,相较于本人之前博客中提到的几篇博文,本人感觉这篇文章更清楚地说明了KMP算法的来龙去脉. http://www.cnblogs.com/goagent/archive/ ...

  6. 真正理解KMP算法

    作者:jostree 转载请注明出处 http://www.cnblogs.com/jostree/p/4403560.html 所谓KMP算法,就是判断一个模式串是否是一个字符串的子串,通常的算法当 ...

  7. KMP算法 --- 深入理解next数组

    在KMP算法中有个数组,叫做前缀数组,也有的叫next数组. 每一个子串有一个固定的next数组,它记录着字符串匹配过程中失配情况下可以向前多跳几个字符. 当然它描述的也是子串的对称程度,程度越高,值 ...

  8. 从有限状态机的角度去理解Knuth-Morris-Pratt Algorithm(又叫KMP算法)

    转载请加上:http://www.cnblogs.com/courtier/p/4273193.html 在开始讲这个文章前的唠叨话: 1:首先,在阅读此篇文章之前,你至少要了解过,什么是有限状态机, ...

  9. KMP算法的一次理解

    1. 引言 在一个大的字符串中对一个小的子串进行定位称为字符串的模式匹配,这应该算是字符串中最重要的一个操作之一了.KMP本身不复杂,但网上绝大部分的文章把它讲混乱了.下面,咱们从暴力匹配算法讲起,随 ...

随机推荐

  1. HDU 3351 Seinfeld(括号匹配)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3351 解题报告:输入一个只有'{'跟'}'的字符串,有两种操作,一种是把'{'变成'}',另一种是'} ...

  2. Unix操作系统中UUCP知识详细讲解

    导读 Unix操作系统有很多值得学习的地方,这里我们主要介绍Unix操作系统中的uucp,大家一起来学习下吧!UUCP系统是一组程序,完成文件传输,执行系统之间的命令,维护系统使用情况的统计,保护安全 ...

  3. Understand:高效代码静态分析神器详解(转)

    之前用Windows系统,一直用source insight查看代码非常方便,但是年前换到mac下面,虽说很多东西都方便了,但是却没有了静态代码分析工具,很幸运,前段时间找到一款比source ins ...

  4. Android之NetworkOnMainThreadException异常

    看名字就应该知道,是网络请求在MainThread中产生的异常 先来看一下官网的解释: Class Overview The exception that is thrown when an appl ...

  5. TP中的四种url访问方式

    什么是PATHINFO:就是http://localhost/index.php/Home/Index/index/a/1/b/2?c=3中的红色部分, 注意c=3并不是pathinfo的一部分,它是 ...

  6. Qt 官方一键动态发布技能

    苦找了好几天动态库,程序可以运行了,结果没有图标还是少了运行库很苦恼,发现Qt 官方有一键动态发布功能感觉自己萌萌的,来自qt吧亲测可用. 集成开发环境 QtCreator 目前生成图形界面程序 ex ...

  7. js之作用域和面向对象

    作用域 JavaScript以函数为作用域 函数的作用域在函数未被调用之前,已经创建 函数的作用域存在作用域链,并且也是在被调用之前创建 示例一 xo = "alex"; func ...

  8. 微博地址url(id)与mid的相互转换 Java版

    原理: 新浪微博的URL都是如:http://weibo.com/2480531040/z8ElgBLeQ这样三部分. 第一部分(绿色部分)为新浪微博的域名,第二部分(红色部分)为博主Uid,第三部分 ...

  9. ajaxfileupload回到json带<pre>

    ajaxfileupload返回json带<pre> 老系统,将文件上传方式修改为ajax上传,调用ajaxfileupload.js 出错现象: 文件正常提交,后台接收正常,action ...

  10. 转: 认识 HTTPS

    HTTPS简介 HTTPS(全称:Hyper Text Transfer Protocol over Secure Socket Layer),是以安全为目标的HTTP通道,简单讲是HTTP的安全版. ...