KMP next数据mark
看了好多遍的next数组,还是不清楚,简单mark一下
- next数组计算的是当前字符前面的字符串的最长匹配头和尾
- next[0]=-1
- next[[1]]=-1
def get_next(needle):
n_len = len(needle)
next = [0 for i in range(n_len)]
j = -1
i = 0
next[i] = -1
while i < n_len - 1:
if j == -1 or needle[i] == needle[j]:
j += 1
i += 1
next[i] = j
else:
j = next[j]
return next
以aaabaabab为例说明next计算过程:
- 如上数组所述,needle为需要计算next的数组,首先初始化next[0]=-1,一开始j==1进入循环,j = 0, i = 1,next[1] = 0,
当i下标移动到1,j为0时,此时需要计算next[2]的值,比较位置为2的字符前面的字符串的最大头和尾,比较needle[1] 是否等于needle[0],等于,则i = 2, j = 1, next[2] = 1。 - 然后计算next[3],判断位置为3的字符前面的字符串的最大公共头和尾,此时已经计算得到位置为2的字符的前面的字符串的最大公共头和尾,则我们将上一步的得到的头和尾分别向后移动一步,看是否相同,即上一步的i+=1 和j+=1,可以想象,此操作就是对前一步的得到的头和尾分别再加一个字符串判断是否相等,next[2] = 1, 则此时比较needle[2] == needle[1]吗?等于,则 j += 1, i += 1, next[3]=2,(这时候我们可以看到,needle[3](字符b)前面的aa和从头开始的aa是相同的,即是最长的公共头和尾)
- 此时 i = 3, j = 2, 进入下一次循环,此时先判断上一步得到的最长头和尾分别在加一个字符是否相同,发现不是,此时保证当前i位置不变(此时的i即为下一步要计算的next的前面字符串的最后一位),将j返回到next[j]匹配的最大头处,即j = next[j] = next[2] = 1, 然后比较needle[3] == needl[1]吗?不等于 则j继续前移, j = next[1] = 0, 此时比较needle[3] == needle[0]吗?不等于,则j继续前移, j = next[0] = -1, 此时已无前缀字符串,则j+=1, i+=1, next[4] = 0
- 此时我们得到的是next[0]=-1, next[1]=0 next[2]=1, next[3]=2, next[4] = 0,此时 i = 4, j = 0, 判断needle[4] == needle[0]吗?等于,则 i+=1 j += 1, next[5] = 1
- 此时 i = 5, j = 1, 判断needle[5] == needle[1]吗?等于,则 i+=1 j += 1, next[6] = 2,此时得到的是next[0]=-1, next[1]=0 next[2]=1, next[3]=2, next[4] = 0,next[5] = 1,next[6] = 2
- ……
- 依次执行比较,最后得到的是next = [-1, 0, 1, 2, 0, 1, 2, 0, 1]
最后的核心原理还是判断当前字符前面的字符串的最长公共头和尾