扩展kmp--Z函数

本文介绍了如何使用暴力循环和扩展KMP算法计算字符串的最长公共前缀。暴力方法通过逐个字符比较,而扩展KMP利用已知信息优化搜索过程。Manacher算法在此背景下有所启发。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. 定义

我们约定对于字符串 s s s,长度为 s z sz sz

s [ i : ] s[i:] s[i:] s i s i + 1 ⋯ s s z − 1 s_is_{i+1}\cdots s_{sz-1} sisi+1ssz1

z z z函数定义为

s [ 0 : ] 与 s [ i : ] s[0:]与s[i:] s[0:]s[i:]的最长公共前缀长度。

2. 实现

2.1 暴力

直接从前往后暴力循环

std::vector<int> ExtendKmp::z_function_trivial(std::string s) {

    int sz = static_cast<int>(s.size());
    std::vector<int> z(sz, 0);


    for (int i = 1;i < sz; ++i) {
        while ( i + z[i] < sz && s[z[i]] == s[i + z[i]])
                z[i]++;
    }


    return z;
}
2.2 扩展kmp

实际上与 k m p kmp kmp好像没啥关系?感觉跟 m a n a c h e r manacher manacher有点像。

核心的思想就是,当 i + z [ i ] > j i+z[i]>j i+z[i]>j时, z [ j ] = z [ j − i ] z[j] =z[j-i] z[j]=z[ji]

假设前缀区间为 [ l , r ] [l,r] [l,r]

r > i r>i r>i时, s [ i , r ] = s [ i − l , r − l ] , z [ i ] = z [ i − l ] s[i,r]=s[i-l,r-l],z[i]=z[i-l] s[i,r]=s[il,rl],z[i]=z[il]
r < = i r <=i r<=i时,$$

std::vector<int> ExtendKmp::z_function(std::string s) {

    int sz = static_cast<int>(s.size());
    std::vector<int> z(sz, 0);

    int l = 0, r = 0;

    for (int i = 1; i < sz; ++i) {
        if ( i <= r && i + z[i - l] + 1 < r) {
            z[i] = z[i - l];
        } else{
            z[i] = std::max(0, r - i + 1);

            while (i + z[i] < sz && s[z[i]] == s[i + z[i]])
                ++z[i];
        }

        if ( i + z[i] > r) {
            l = i;
            r = i + z[i] ;
        }
    }

    return z;
}

3. Ref

oi-wiki

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值