7.9 ACM-ICPC字符串算法 Z 函数(扩展 KMP)

7.9 ACM-ICPC字符串算法 Z 函数(扩展 KMP)

在算法竞赛中,字符串处理是一个核心主题,特别是在ACM-ICPC比赛中。今天我们将深入探讨Z函数,这是扩展KMP算法的基础,用于字符串匹配。本文将通过理论介绍和示例代码帮助你理解和实现这一重要的算法。

简介

Z函数,也称为Z数组,是一个非常实用的字符串处理工具,用于解决各种字符串匹配问题,包括查找字符串的所有出现位置、字符串压缩和模式匹配等。它通过扩展KMP算法(也称为扩展的Knuth-Morris-Pratt算法)来优化计算过程。

Z函数定义

对于一个字符串 S 的 Z 函数,我们定义 Z[i] 为字符串 S 与从位置 i 到末尾的子串 S[i...] 的最长公共前缀(LCP)的长度。特别地,Z[0] 通常设置为 0 或字符串的长度。

Z函数的计算方法

为了计算Z函数,我们可以使用一种高效的单遍扫描方法,时间复杂度为 O(n)。以下是计算过程:

  1. 初始化:设置 Z[0] = 0(或整个字符串的长度),定义区间 [L, R],最初设为 [0, 0]。
  2. 对于每个 i 从 1 到 n-1:
    • 如果 i > R,通过逐字符比较计算 Z[i],然后更新 [L, R]。
    • 如果 i ≤ R,令 k = i - L,并使用之前的 Z[k] 来初步设定 Z[i]
      • 如果 Z[k] < R-i+1,则 Z[i] = Z[k]
      • 如果 Z[k] >= R-i+1,则需要从 R 后面开始比较,更新 Z[i] 并调整 [L, R]。
  3. 更新 [L, R]:如果通过新计算的 Z[i],有 i + Z[i] - 1 > R,则更新 L = iR = i + Z[i] - 1

示例代码

#include <iostream>
#include <vector>
#include <string>

std::vector<int> compute_Z(const std::string& S) {
    int n = S.length();
    std::vector<int> Z(n, 0);
    int L = 0, R = 0, K = 0;
    for (int i = 1; i < n; ++i) {
        if (i > R) {
            L = R = i;
            while (R < n && S[R] == S[R - L]) {
                R++;
            }
            Z[i] = R - L;
            R--;
        } else {
            K = i - L;
            if (Z[K] < R - i + 1) {
                Z[i] = Z[K];
            } else {
                L = i;
                while (R < n && S[R] == S[R - L]) {
                    R++;
                }
                Z[i] = R - L;
                R--;
            }
        }
    }
    return Z;
}

int main() {
    std::string text = "abcabcabc";
    std::vector<int> Z = compute_Z(text);
    std::cout << "Z array: ";
    for (int z : Z) {
        std::cout << z << " ";
    }
    std::cout << std::endl;
    return 0;
}

应用场景

Z函数可以应用于多种字符串处理问题,例如:

  • 搜索字符串模式:通过将模式和目标文本串联起来,我们可以使用Z函数快速找到模式在文本中的所有出现。
  • 字符串相似度检查:通过计算Z函数,可以快速判断两个字符串的相似度或者公共前缀长度。
  • 数据压缩:对重复出现的模式进行分析和编码时,Z函数提供了一种高效的方式。

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

夏驰和徐策

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

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

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

打赏作者

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

抵扣说明:

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

余额充值