我们学习了没有改进的KMP算法后,可以知道通过NEXT[ ] 数组可以有效降低时间复杂度,将其从简单模式匹配的O(MN)降低为(M+N),那么,他是如何计算NEXT[ ] 的值呢?
我们假设有一串主串‘abaabb’,主串的指针为i,模式串的指针为j。那么我们可以知道,NEXT[ ] 中应该填入j,即NEXT[ j ]。在KMP算法中,通过学习得知,主串指针i是不会变小的。
这里介绍一种快速手算KMP算法中的NEXT[ ]数组手算方法:
假设主串为‘abaabb’,主串指针默认为i,模式串指针默认为j。我们使用的是严老师的数据结构所讲的,那么NEXT[ j ]数组起始是NEXT[ 1 ]=0(这是默认的),由此我们可以无脑写出NEXT[2]=1。
在KMP算法中,计算模式串abaabb
的next数组(从1开始计数,且next[1] = 0)的过程如下:
-
初始化:
-
主串索引:
1: a, 2: b, 3: a, 4: a, 5: b, 6: b
-
next[1] = 0,next[2] =1
。(无脑写) -
next[]数组值为next[j+1],最大值也next[j+1],即如果当前位置(如在计算第10个索引时,第二个索引位置已经为next[2]了)最大next数组为next[2],那么下一个位置的(第11个索引位置)最大值只能为next[3]。可以小于等于3,不能超过3。
-
-
计算步骤(在计算过程中,计算第i个位置时,从第i-1个位置开始看,不看第i这个位置):
根据当前需计算索引的前一个索引下next数组的值来计算。
分为前缀和后缀。
如:aba,已经知道我们需要计算‘aba’的next数组,已知‘ab’的next数组在‘b’这位置的值为1,那么我们这样画一个括号,即‘ab)a’,来计算‘)’后的a的next数组的值,这样方便看。相当于现在的前缀就是第一个‘a’,后缀为‘b’,因为‘ab’的next数组在‘b’这位置的值为1,所以只拿从前缀往后数的一个元素,即‘a’本身,同理,拿出后缀往前数的第一个元素,即‘b’本身。‘a’和‘b’不想等,所以当前索引值下的next数组值为0+1=1。
同理,‘abaab’的第二个‘b’的next数组值为2。计算如下:
在第二个b前画个括号,即‘abaa)b’,前缀为第一个‘a’,后缀为第三个‘a’,已经知道了第四个索引(第三个‘a’)位置的next数组的值为2,所以我们要匹配从前缀开始数的前两个元素,即'ab',同理,从后缀开始数两个元素'aa'(后缀是从后往前数,但是拿出来是从前往后拿,例如abcdef,从后缀开始数三个元素拿出来之后是‘dfe’!!!)接下来匹配从前缀中取出来的两个元素和从后缀取出来的两个元素,很显然'aa'≠‘ab’,所以当前next数组的值减1,从2变为1,接下来从前缀开始往后数,取出一个元素,即前缀'a'(主串中索引为1的‘a’),同理,后缀也取出一个元素,即后缀‘a’(主串中索引为4的‘a’),很显然,‘a’=‘a’,那么此时的next数组的值就为1+1=2,所以在‘abaab’索引为5即第二个‘b’的位置的next数组的值为2。
最终next数组:next = [0, 1, 1, 2, 2, 3] (索引从1到6)