Z算法(EXKMP)

Z算法(EXKMP)

爆肝计划

刚开始接触时,疑惑于Z算法和EXKMP,二者的作用基本相似,我就想,既然起了不一样的名字,那么他们的解题思路必然不一样吧。

我又经过了网上大量收集资料,发现有的大佬是两个和一块成一个感念,有的是单独讲一个,这让我小蒟蒻很为难,最后在大佬的指路下去了去了OI WIKI,然后知道他俩是合在一块的,连接再此

但是EXKMP多了next数组,为了方便,在这里就开始讲z算法吧

1.首先我们要明白z算法是一种用于字符串区配的算法,是对字符串S,O(n)地求出S的全体后缀与S自身的最长公共前缀的长度,记录在数组z[]中(z[i]即后缀 i与S的最长公共前缀的长度)。

2.话不多说,上图(字丑,见谅)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

从上面我们可以得到这么规律

1.假设i>R,则说明不存在一个结束于i或者i之后的串,同时这个串本身也为s的一个前缀,否则R不应该小于i。对于这种情况,需要重新计算新的L与R,令L=R=i,暴力比较s与suffix(i),得到z[i]=R-i+1=R-L+1。

2.此时i<=R,令k=i-L,可以断言z[i]>=min(z[k],R-i+1)。因为根据L与R的含义,此时我们可以将L到R视作为字符串的前缀,那么i相对于L的偏移量为k。

如果z[k]<R-i+1,则z[i]必然等于z[k],基于此时,s[k,k+z[k]-1]是s[i,R]的一个前缀,同时在这种情况下L与R不变。

如果z[k]>=R-i+1,根据R的含义可知s[R+1]!=s[R-L+1],z[k]中大于R-i+1的匹配信息因为s[R+1]!=s[R-L+1]而无效,但这并不意味着s[R+1]!=s[R-i+1],此时根据z[k]可以断言z[i]至少是R-i+1,是否可以更大需要再进行计算,令L=i,更新R值,并得到此时的z[i]。

目前并没有什么只用这算法的例题,那么先把模板代码贴上把,能够实现求z数组


void z_init(){//求z数组
    z[1]=n;//特殊处理z[1]
    int zl=0,zr=0;//右端点最大
    for(int i=2;i<=n;i++)//从i=2递推到i=n
        if(zr<i){//第1种情况
            z[i]=0;
            while(i+z[i]<=n&&a[i+z[i]]==a[1+z[i]])z[i]++;//直接向后暴力匹配
            if(z[i])zl=i,zr=i+z[i]-1;//更新右端点
        }
        else if(i+z[i-zl+1]<=zr)z[i]=z[i-zl+1];//第2种情况的第1种情况
        else{//第2种情况的第1种情况
            z[i]=zr-i+1;//z[i]至少有zr-i+1
            while(i+z[i]<=n&&a[i+z[i]]==a[1+z[i]])z[i]++;//后面再暴力匹配
            zl=i;zr=i+z[i]-1;//更新右端点
        }
}

欢迎留言哟ヾ(≧▽≦*)o

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值