z函数总共有三种情况,分开讨论。
可以通过这个链接来模拟理解z函数的过程z函数模拟
func getZ(s string) []int {
n := len(s)
//z[0]默认就为0
z := make([]int, n)
//标识z-box的左右边界
l, r := 0, 0
for i := 1; i < n; i++ {
//第1,2种情况,首先i要在z-box范围内
if i <= r {
//1.z[i-l]没有超过z-box长度的边界,那么z[i]=z[i-l]
//2.z[i-l]超过z-box长度的边界,此时就先让z[i]=r-i+1,因为此时还不确定超过边界后是否还是相等的
z[i] = min(z[i-l], r-i+1)
}
//第2种情况会在这里继续判断z-box边界以外的字符是否相等
//第3种情况就是i在z-box范围外,那么就判断字符是否相等
//目的是让r尽可能的大,因为这样才可以让后续的字符可能利用上z-box,这样就可以减少时间复杂度
for i+z[i] < n && s[z[i]] == s[i+z[i]] {
//如果能够匹配的上前缀,那么就要更新z-box的范围,范围就是匹配的子串
l, r = i, i+z[i]
//z[i]代表的是长度,还需要在下标的基础上+1
z[i]++
}
}
return z
}