KMP-两种方法求next数组

文章目录

  • 前言
  • 最佳最快方法
    • 原理
    • 方法详述
    • 分析和思考
    • 其他的next数组
    • 总结
  • 最好理解记忆方法
    • 原理
      • 前缀字符串和后缀字符串
      • 部分匹配值
      • next数组意义
    • 方法详述
  • 测试链接

前言

作为408考生,数据结构绕不开KMP算法,网上各种求next数组的方法和结果竟各有不同,本文将带你探讨产生这种局面的原因和求next数组的两种方法。

最佳最快方法

原理

我没去找,反正算的确实是对的。

方法详述

  1. 求模串abaababb的next数组,设置表如下
    KMP-两种方法求next数组_第1张图片

  2. 分别设置next[1]和next[2]的值为0和1
    KMP-两种方法求next数组_第2张图片

  3. 要求i位置next值时,观察前一个位置,即i-1位置。
    (1). 设置一个固定指针指向i-1位置,一个移动指针j首先指向i-1。
    (2). 如果i-1位置的字符和j位置next指向的字符相同,则设置next为j位置next值+1。
    (3). 如果不相同则让j指针移动。移动到目前next指向的位置。直到i-1位置的字符和j位置next指向的字符相同或者j位置next指向0,则设置next为j位置next值+1。

如:这里求序号3的next值,则观察序号2的next值,发现其next值指向序号1。
而序号1对应的字符a与序号2对应的字符不相同,故j继续移动,但此时发现
序号1的next为0,已经不能再往前了。故next取此时j指向的next+1。即0+1=1

KMP-两种方法求next数组_第3张图片

  1. 以下是相同时的情况
    KMP-两种方法求next数组_第4张图片

  2. 后续过程如下图,求取过程为:红绿黄黑
    KMP-两种方法求next数组_第5张图片
    KMP-两种方法求next数组_第6张图片
    KMP-两种方法求next数组_第7张图片
    KMP-两种方法求next数组_第8张图片

分析和思考

上面的案例可能不好理解,不过我们可以得出以下几个结论帮助理解(假设要求第i位置的字符):

  1. 求next值不需要知道第i位置及以后的字符,只需要利用第i位置以前的字符和其对应的next值。
  2. 被比较的字符是i-1位置的字符,它是一直不会变的。比较字符一开始是i-1的next指向的字符,它会因条件不符合(即被比较字符与比较字符不同)而通过next改变。
  3. 最后条件符合(即被比较字符与比较字符相同)时next取决于索引到比较字符的next(即图中的绿色箭头的起点,而不是终点)。

那么第一个字符和第二个字符next值的0和1又从而来呢?
第二字符的next很容易就可以知道:求其next值时只需要考虑第一个字符,因第一个字符前面所以不到其他字符了,所以第二个字符的next值就是第一个字符的next值+1。
那么第一个字符呢?第一个字符前面已经没有字符了,所以我们无法通过这种方法得到第一个字符的next值,而要追根溯源通过原理解释,所以想知道这个问题请看第二种方法。

其他的next数组

在其他人的文章中你或许会看到同一模串会有不同的next数组。比如:对于ababaaababaa对应的next数组可能会有-1,0,0,1,2,3,1,1,2,3,4,5和0,1,1,2,3,4,2,2,3,4,5,6两种形式,但是仔细观察就会发现两个数组每个元素都相差1,那么到底哪个才是正确答案呢?
答案是:两个都有可能!会造成的这样差别的原因是数组教学中的经典问题——数组下标到底是从0还是1开始!第一个是数组从0开始的程序结果,第二个是数组从1开始的手算结果。

如果你已经充分理解了这种方法,请尝试自己编程实现一下吧!

总结

这个方法简而言之就是:在通过前一个字符next串成的链中寻找第一个和前一个字符相同的结点。

最好理解记忆方法

原理

当模串指针移动到j位置时匹配失败了,说明至少主串的指针i前面长度为j-1的子串和模串是相同的。那我们是否可以利用前面这段匹配相同的信息呢?显然是可以的,分析相同前后缀子串就是其中一种方法:如图,当我们发现j指针处不匹配了,需要将j指针向前移动。明显,主串的i-1、i-2、i-3与模串的123位置的字符是一样的。
KMP-两种方法求next数组_第9张图片
那么我们可以直接将j回溯到4位置进行对比。
KMP-两种方法求next数组_第10张图片

但是主串的匹配项不尽相同,而模串的总是一样的,所以我们只用转而求相对主串短很多的模串的相同前后缀就行了。

这个方法源自于KMP的原理,易于理解但是求解过程复杂费时,所以不建议考试用这种方法。如果了解KMP和next原理的同学可以直接跳过这个部分。

前缀字符串和后缀字符串

前缀字符串即除本身外可以构成前缀的串。
后缀字符串即除本身外可以构成后缀的串。

例:对于串 abcde,前缀字符串集={abcd,abc,ab,a},后缀字符串集={bcde,cde,de,e}。

部分匹配值

这是KMP算法早期利用的模串信息,即next数组的前身。

部分匹配值=前缀字符串和后缀字符串最长相同子串的长度。

例:对于串 ababa,前缀字符串集={abab,aba,ab,a},后缀字符串集={baba,aba,ba,a}。最长相同子串为aba。故部分匹配值为3。

next数组意义

next数组又称前缀数组。
数值意义:它代表匹配失败时,模串指针该回溯的位置。
原理意义:它分析该字符前面的字符构成的子串中的最长相同前后缀子串。

方法详述

今天没时间了,下次再写。

测试链接

我写了一个简单的h5页面挂在unicloud上,可以获取输入字符串的next和nextval数组,对自己想法有疑惑的兄弟可以测一测。
如果你认为测试结果有问题可以私信我,毕竟赶急写的,难免会有些问题。
next数组测试网站

你可能感兴趣的:(数据结构,数据结构)