Z函数(扩展KMP)的模板(参考)

简单来说这玩意就是对一个长度为n的字符串s,计算s的从第i个字符开始的后缀和原字符串s的最长公共子串(i = 1,2,……n),然后拿这个东西来计算别的东西的

知识点可以参考:Z 函数(扩展 KMP) - OI Wiki

代码如下:

#ifndef __ZFUNCTION__
#define __ZFUNCTION__

#include<vector>
#include<string>
#include<algorithm>

struct ZFunction{
    std::string s;
    std::vector<int> z;
    
    void getZ(void);
    ZFunction(){}
    ZFunction(std::string s):s(s){this->getZ();}
    std::vector<int> matchSubString(const std::string &p);
    int cntDiffSubstring(void);
    int getPeriod(void);
};

void ZFunction::getZ(void){
    int n = s.size(); z.resize(n, 0);
    for(int i = 1, l = 0, r = 0; i < n; i++){
        if(i <= r && z[i - l] <= r - i + 1) z[i] = z[i - l];
        else{
            z[i] = std::max(0, r - i + 1);
            while(i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
        }
        if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
    }
}
std::vector<int> ZFunction::matchSubString(const std::string &p){
    ZFunction tmp(p + "\0" + s); std::vector<int> ans; int len = p.size();
    for(int i = 0; i < s.size(); i++)
        if(z[i + len + 1] == len) ans.push_back(i);
    return ans;
}//检测p在s中出现的位置(其中p和s中不能有'\0',如果有,可以按需修改)
int ZFunction::cntDiffSubstring(void){
    std::string s_t; int ans = 0;
    for(int i = 0; i < s.size(); i++){
        s_t = s[i] + s_t;
        ZFunction z_t(s_t);
        int maxn = 0;
        for(int i = 0; i < z_t.z.size(); i++)
            maxn = std::max(maxn, z_t.z[i]);
        ans += s_t.size() - maxn;
    }
    return ans;
}//计算s的本质不同子串数
int ZFunction::getPeriod(void){
    int n = z.size();
    for(int i = 0; i < n; i++)
        if(i + z[i] == n) return i;
    return n;
}//计算字符串整周期

#endif

其实我写这个东西,一来是为了复习一下知识点,看看自己能不能复现Z函数

二来是为了缓解学习数据分析的苦闷(准确来说是学numpy和pandas),没有可以拿来练手的东西看着真的很困

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值