【转载】https://blog.csdn.net/LEE18254290736/article/details/77278769

对于正常的字符串模式匹配,主串长度为m,子串为n,时间复杂度会到达O(m*n),而如果用KMP算法,复杂度将会减少线型时间O(m+n)。

设主串为ptr="ababaaababaa";,要比较的子串为a=“aab”;

KMP算法用到了next数组,然后利用next数组的值来提高匹配速度,我首先讲一下next数组怎么求,之后再讲匹配方式。

next数组详解

首先是理解KMP算法的第一个难关是next数组每个值的确定,这个问题困恼我很长时间,尤其是对照着代码一行一行分析,很容易把自己绕进去。

定义一串字符串

ptr = "ababaaababaa";

next[i](i从1开始算)代表着,除去第i个数,在一个字符串里面从第一个数到第(i-1)字符串前缀与后缀最长重复的个数。

什么是前缀?

在“aba”中,前缀就是“ab”,除去最后一个字符的剩余字符串。

同理可以理解后缀。除去第一个字符的后面全部的字符串。

在“aba”中,前缀是“ab”,后缀是“ba”,那么两者最长的子串就是“a”;

在“ababa”中,前缀是“abab”,后缀是“baba”,二者最长重复子串是“aba”;

在“abcabcdabc”中,前缀是“abcabcdab”,后缀是“bcabcdabc”,二者最长重复的子串是“abc”;

这里有一点要注意,前缀必须要从头开始算,后缀要从最后一个数开始算,中间截一段相同字符串是不行的。

再回到next[i]的定义,对于字符串ptr = "ababaaababaa";

next[1] = -1,代表着除了第一个元素,之前前缀后缀最长的重复子串,这里是空 ,即"",没有,我们记为-1,代表空。(0代表1位相同,1代表两位相同,依次累加)。

next[2] = -1,即“a”,没有前缀与后缀,故最长重复的子串是空,值为-1;

next[3] = -1,即“ab”,前缀是“a”,后缀是“b”,最长重复的子串“”;

next[4] = 1,即"aba",前缀是“ab”,后缀是“ba”,最长重复的子串“a”;next数组里面就是最长重复子串字符串的个数

next[5] = 2,即"abab",前缀是“aba”,后缀是“bab”,最长重复的子串“ab”;

next[6] = 3,即"ababa",前缀是“abab”,后缀是“baba”,最长重复的子串“aba”;

next[7] = 1,即"ababaa",前缀是“ababa”,后缀是“babaa”,最长重复的子串“a”;

next[8] = 1,即"ababaaa",前缀是“ababaa”,后缀是“babaaa”,最长重复的子串“a”;

next[9] = 2,即"ababaaab",前缀是“ababaaa”,后缀是“babaaab”,最长重复的子串“ab”;

next[10] = 3,即"ababaaaba",前缀是“ababaaab”,后缀是“babaaaba”,最长重复的子串“aba”;

next[11] = 4,即"ababaaabab",前缀是“ababaaaba”,后缀是“babaaabab”,最长重复的子串“abab”;

next[12] = 5,即"ababaaababa",前缀是“ababaaabab”,后缀是“babaaaababa”,最长重复的子串“ababa”;

还有另外一种方法,我看的有的书上写着:

这里我们定义next[1] = 0 , next[1] = 1;

再分析ptr字符串,ptr = "ababaaababaa";

跟上一个的情况类似,

next[1] = 0 ,事先定义好的

next[2] = 1 ,事先定义好的

next[3] = 1 ,最长重复的子串“”;1代表没有重复,2代表有一个字符重复。

next[4] = 2 ,最长重复的子串“a”;追偿的长度加1,即为2.

next[5] = 3 ,以下都跟之前的一样,这种方法是最长的长度再加上一就可以了。

next[6] = 4

next[7] = 2

next[8] = 2

next[9] = 3

next[10] = 4

next[11] = 5

next[12] = 6

以上是next数组的详细解释。next数组求值 是比较麻烦的,剩下的匹配方式就很简单了。

next数组用于子串身上,根据上面的原理,我们能够推出子串a=“aab”的next数组的值分别为0,1,2.(按照我说的第二种方式算的)。

首先开始计算主串与子串的字符,设置主串用i来表示,子串用j来表示,如果ptr[i]与a[i]相等,那么i与j就都加1:

prt[1]与a[1]相等,i++,j++:

用代码实现就是

  1. if( j==0 ||  ptr[i]==a[j])
  2. {
  3. ++i;
  4. ++j;
  5. }

ptr[2]与a[2]不相等

此时ptr[2]!=a[2],那么令j = next[j],此时j=2,那么next[j] = next[2] = 1.那么此时j就等于1.这一段判断用代码解释的话就是:

  1. if( ptr[i]!=a[j])
  2. {
  3. j = next[j];
  4. }

加上上面的代码进行组合:

在对两个数组进行比对时,各自的i,j取值代码:

  1. <span style="font-size:18px;">while( i<ptr.length && j< a.length)
  2. {
  3. if( j==0 || ptr[i]==a[i] )
  4. {
  5. ++i;
  6. ++j;</span>
  1. <span style="font-size:18px;">          next[i] = j;
  2. }
  3. else
  4. {
  5. j = next[j];
  6. }
  7. }</span>

此时将a[j]置于j此时所处的位置,即a[1]放到j=2处,因为在j=2时出现不匹配的情况。

此时再次计算是否匹配,可以看出来a[1]!=ptr[2],那么j = next[j],即此时j = next[1] = 0;

根据上面的代码,当j=0时,执行++i;++j;

此时就变为:

此时ptr[3] = a[1],继续向下走,下一个又不相等了,然后“aab”向后挪一位,这里不再赘述了,主要的思想已经讲明白了。到最后一直到i = 8,j=3时匹配成功,KMP算法结束。整个过程就结束了。

【转载】KMP入门级别算法详解--终于解决了(next数组详解)的更多相关文章

  1. ES6_入门(4)_数组的解构赋值

    //2017/7/14 //变量的解构赋值(解构:Destructuring) //(1)数组的解构赋值 let [a,b,c]=[1,2,3];//模式匹配,只要等号两边的模式相同,左边的变量就会被 ...

  2. 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不吐不快

    http://www.cnweblog.com/fly2700/archive/2011/12/06/318916.html (转载) 花了5天时间,终于解决了一个bug,心情非常愉快,憋了这么久,不 ...

  3. 转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解

    目标大纲 文章转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解 IE中CSS-filter滤镜小知识大全 CSS实现跨浏览器兼容性的盒阴影效果

  4. 转载 - KMP算法

    出处:http://www.cnblogs.com/dolphin0520/archive/2011/08/24/2151846.html KMP算法 在介绍KMP算法之前,先介绍一下BF算法. 一. ...

  5. 【原创】视频+文字:详解VBA解决数独问题

    [说在前面]: 之前,我在微信朋友圈看到一个同事发了一个状态,说的是她在家辅导孩子做作业,一个数独的题目,好像没有做出来.我看了下,我也做不出来,后来仔细想了下,花了两个多小时时间,用Python编了 ...

  6. spring事务详解(三)源码详解

    系列目录 spring事务详解(一)初探事务 spring事务详解(二)简单样例 spring事务详解(三)源码详解 spring事务详解(四)测试验证 spring事务详解(五)总结提高 一.引子 ...

  7. 大话数据结构(8) 串的模式匹配算法(朴素、KMP、改进算法)

    --喜欢记得关注我哟[shoshana]-- 目录 1.朴素的模式匹配算法2.KMP模式匹配算法 2.1 KMP模式匹配算法的主体思路 2.2 next[]的定义与求解 2.3 KMP完整代码 2.4 ...

  8. [转载]花了半个月,终于把Python库全部整理出来了,非常全面

    库名称简介 Chardet 字符编码探测器,可以自动检测文本.网页.xml的编码. colorama 主要用来给文本添加各种颜色,并且非常简单易用. Prettytable 主要用于在终端或浏览器端构 ...

  9. 服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

    转载的服务器TIME_WAIT和CLOSE_WAIT详解和解决办法

随机推荐

  1. Consonant Fencity Gym - 101612C 暴力二进制枚举 Intelligence in Perpendicularia Gym - 101612I 思维

    题意1: 给你一个由小写字母构成的字符串s,你可以其中某些字符变成大写字母.如果s中有字母a,你如果想把a变成大写,那s字符串中的每一个a都要变成A 最后你需要要出来所有的字符对,s[i]和s[i-1 ...

  2. P1714 切蛋糕 dp+单调队列

    题意: 题目描述 在幻想乡,琪露诺是以笨蛋闻名的冰之妖精. 某一天,琪露诺又在玩速冻青蛙,就是用冰把青蛙瞬间冻起来.但是这只青蛙比以往的要聪明许多,在琪露诺来之前就已经跑到了河的对岸.于是琪露诺决定到 ...

  3. zjnu1735BOB (单调队列,单调栈)

    Description Little Bob is a famous builder. He bought land and wants to build a house. Unfortunately ...

  4. POJ 2195 & HDU 1533 Going Home(最小费用最大流)

    这就是一道最小费用最大流问题 最大流就体现到每一个'm'都能找到一个'H',但是要在这个基础上面加一个费用,按照题意费用就是(横坐标之差的绝对值加上纵坐标之差的绝对值) 然后最小费用最大流模板就是再用 ...

  5. linux搭建网站

    CentOS 1.安装 yum -y install nginx *或者安装指定版本,版本网址:http://nginx.org/packages/centos/7/x86_64/RPMS/ rpm ...

  6. HDU 3681 Prison Break(状压DP + BFS)题解

    题意:一张图,F是起点,Y是必须要到的点,D不能走,G可以充电.可以往四个方向走,每走一步花费一个电,走到G可以选择充满电或者不充,每个G只能充一次.问你走遍Y的最小初始点亮.number(G) + ...

  7. git操作是出现Username for 'https://github.com':的验证问题

    Username for 'https://github.com': 输入的是github上的邮箱账号, 而不是github中设置的username, 这是个巨坑!!!Password for 'ht ...

  8. μC/OS-III---I笔记3---时间管理

    时间管理相关函数,其实深入根本的理解就是一些对时间任务相关变量,数据结果进行修改的函数这样方便对应任务查找延时等时间相关的任务有没有到期.前面的时间相关的函数是这些操作的基 1.延时函数 OsTIme ...

  9. webpack OSS All In One

    webpack OSS All In One 阿里云 OSS 对象存储(Object Storage Service,简称OSS),是阿里云对外提供的海量.安全和高可靠的云存储服务 https://c ...

  10. CSS 检测 IE 浏览器

    CSS 检测 IE 浏览器 <!--[if IE]> <link href="ie.css" rel="stylesheet"> < ...