字符串与子字符串前缀匹配算法Z-algorithm(比较难理解)

问题

对于一个字符串s,设它的长度为len

z[i]所表示的是s[i…len-1]与s[0…len-1]的最长公共前缀

如何求出z[i]数组?

在这里插入图片描述

分析

这道题的解法是一个z算法,我也是第一次接触,O(n)的解法能够想到我觉得挺难的,需要通过已知的串s和z[1]…z[i-1]来求z[i],

  • 设想一个z数组,z[i]表示他的最长公共前缀即s[i]…s[i+z[i]].我们将其称之为i这个位置控制的范围,称为一个Z-box。我们定义l,r为右端点最靠右的Z-box的控制范围(即i和i+z[i])。进行分类讨论
  1. 若i > r,则证明前面的所有Z-box和我们没有任何关联,我们无法利用,同时也证明i这个位置的Z-box一定是最靠右的,更新l=r=i,暴力匹配。
  2. 若i < r,则令k=i-l,因为i位于Z-box内,则我们知道s[l]…s[r]应该与s[0]…s[r-l]匹配,所以此处的k对应的是i∈[l,r]这个位置在前缀即[0,r-l]中的对应位置,故我们可以根据z[k]的数值来计算我们的z[i]。令z[i]=min(z[k],r-i+1).Z-box在这里会有两种可能
    • (1)包含。k这个位置控制的Z-box的右端点并没有超过[l,r]这个Z-box的右端点,直接令z[i]=z[k]。
    • (2)超过。k这个位置控制的Z-box的右端点超过了[l,r]对应的前缀。因为我们仅仅知道s[l]…s[r]与s[0]…s[r-l]匹配,后面的部分一概不知,所以我们令l=i,继续暴力匹配后面的长度,匹配完成后令z[i]=r-l即可。

这道题比较难理解,我也不是很懂,哈哈哈,对于z[i]为啥求最小值,举个例子:

s="aaaabaa"
对于i=6的位置,r-i+1=1,Z[1]=3,但是不能把z[6]设置为3,因为显然不是,z[6]的初始化最大值是1,因为它的最大值不会超过r匹配的片段[l,r],所以:
z[i]=min(z[i-l],r-i+1)

代码一(暴力求解)

def z_naive(s):
    Z = [len(s)]
 
    for k in range(1, len(s)):
        n = 0
        while n + k < len(s) and s[n] == s[n + k]:
            n += 1
        Z.append(n)
 
    return Z

代码二 (Z算法)

def get_z(s):
    l=0
    r=0
    n=len(s)
    z=[0]*n
    for i in range(1,n):
        if(i>r):
            l=i
            r=i
            while(r<n and s[r-l]==s[r]):
                r+=1
            z[i]=r-l
            r-=1
        else:
            k=i-l
            if(z[k]<r-i+1):
                z[i]=z[k]
            else:
                l=i
                while(r<n and s[r-l]==s[r]):
                    r+=1
                z[i]=r-l
                r-=1
    return z
def get_z_v1(s):
    n=len(s)
    l=0
    r=0
    z=[0]*n
    for i in range(n):
        if(i<=r):
            z[i]=min(r-i+1,z[i-l])
        while(i+z[i]<n and  s[z[i]]==s[z[i]+i]):
                z[i]+=1
        if(z[i]+i-1>r):
            l=i
            r=z[i]+i-1
    return z

参考文献

[1].Z algorithm (Linear time pattern searching Algorithm). https://www.geeksforgeeks.org/z-algorithm-linear-time-pattern-searching-algorithm/
[2].Z algorithm. https://ivanyu.me/blog/2013/10/15/z-algorithm/
[3].Z-algorithm字符串匹配 算法小结. https://blog.csdn.net/szh_0808/article/details/79257961
[4].Z-function and its calculation.https://cp-algorithms.com/string/z-function.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

农民小飞侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值