exkmp(Z函数) & LCP & LCS

Z函数可以在O(n)时间内求出自己的所有后缀和本身的LCP(最长公共前缀),和任意字符串T和其的LCP。

原理就是考虑之前的lcp,可以通过之前的lcp这一位和前缀某一位一致,对应到前缀某一位的LCP,再向右扩展。注意到,右边界最多被扩展1次所以是线性复杂度。

struct Z {
    int z[MAXN], p[MAXN];
    void get_Z(char* s, int n) {
        int t = 1, lim; z[1] = 1;
        for (int i = 2; i <= n; ++i) {
            lim = t + z[t] - 1; //[1,t-1],[t,lim] 
            if (i + z[i - t + 1] - 1 < lim) {
                z[i] = z[i - t + 1];
            } else {
                z[i] = max(0, lim - i + 1);
                while (s[i + z[i]] == s[z[i] + 1])z[i]++;
            }
            if (i + z[i] > t + z[t])t = i;
        }
        z[1] = n;
    }
    void exkmp(char* s, char* u, int n, int m) {
        int t = 1, lim;
        p[1] = 0;
        for (int i = 1; i <= m; ++i) {
            lim = t + p[t] - 1; //[1,t-1],[t,lim]
            if (i + z[i - t + 1] - 1 < lim) {
                p[i] = z[i - t + 1];
            } else {
                p[i] = max(0, lim - i + 1);
                while (u[i + p[i]] == s[p[i] + 1] && p[i] + 1 <= n)p[i]++;
            }
            if (i + p[i] > t + p[t])t = i;
        }
    }
}p;

例题:
HDU: 7366 Nested String

LCP

性质:

  • 若字符串S,的i后缀和j后缀的LCPji+1(i<j),那么长度为j+LCPi 的子串是以S[i,j1]为周期的串。

更进一步,若字符串iz函数值i+z[i]1=n,那么这个字符串就是以S[1,i1]为周期的串。在后缀章节会学习如何求出任意两个位置的LCP。

  • LCS (最长公共后缀)同理。把字符串翻转一遍,求出LCP即可。
posted on   Quixotica  阅读(45)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示