字符串 (3)--- KMP 算法的扩展

对于个长度为n的字符串s。定义函数zi表示s和si,n-1(即以 si 开头的后缀)的最长公共前缀(LCP)的长度。

z被称为s的Z函数。特别地,z0 = 0。

如同大多数字符串主题所介绍的算法,其关键在于,运用自动机的思想寻找限制条件下的状态转移函数,

使得可以借助之前的状态来加速计算新的状态。

在该算法中,我们从1到n-1顺次计算zi的值(z0=0)。

在计算zi的过程中,我们会利用已经计算好的z0,...,zi-1

对于i,我们称区间i, i+z\[i-1]是i的匹配段,也可以叫Z-box。

算法的过程中我们维护右端点最靠右的匹配段。为了方便,记作 l, r

根据定义,sl, r 是s的前缀。在计算 zi 时我们保证l <= i。初始时l=r=0。

计算完前i-1个z函数,维护Z-box的l, r, 则sl, r = s0, r-l

在计算zi的过程中:

(1)如果 i <= r(在Z-box内),那么根据 l, r 的定义有 si, r = si-l, r-l 同时减l,

因此 zi >= min(zi-l, r-i+1)。

这时:

若 zi-l < r-i+1,则 zi = zi-l

否则 zi-l >= r-i+1,这时我们令 zi = r-i+1,

然后暴力枚举下一个字符扩展 zi 直到不能扩展为止。

(2)如果 i > r(在Z-box外),那么我们直接按照朴素算法,从si开始比较,暴力求出zi

在求出zi后,如果i+zi-1 > r,我们就需要更新l,r,即令 l=i, r=i+zi-1。

当i=4时,l=4,r=5, 我们发现s4\~5==s0\~1,z4==z0,z5==z1

即如果存在si\~r==si-l\~r-l, 可以直接更新zi=zi-l

否则,逐位比较去得出i位置的z函数值

#include <iostream>

#include <vector>

using namespace std;

vector<int> z_fun(string& s)

{

int n = (int) s.length();

vector<int> z(n);

for (int i = 1, l = 0, r = 0; i < n; ++i)

{

if (i <= r)

zi = min (r - i + 1, zi - l); // r-i+1: 右端点r到i的距离

// 逐位比较,字符串下标从0开始,双指针分别指向zi和i+zi

while (i + zi < n && sz\[i] == si + z\[i])

++zi;

if (i + zi - 1 > r)

{

l = i;

r = i + zi - 1;

}

}

return z;

}

int main()

{

string s = "aaabaab";

vector<int> vec = z_fun(s);

return 0;

}

相关推荐
初夏睡觉1 小时前
原创题目 - 空壳恋爱
c++·算法·dp·oi·信息学·原创题目·值得挑战的题目
Buke..1 小时前
【APP 逆向】哔哩哔哩 sign 参数逆向(下):OLLVM 混淆还原 sign 算法
java·javascript·爬虫·python·算法
闲研随记2 小时前
【文献阅读 ICLR 2026】RL算法:DECS
算法·llm·强化学习·iclr·rl
量化小c2 小时前
一行代码查 BTCUSDT 和 AAPL 最新价?QuantDash 统一多市场实时行情接口实战
后端·算法·github
机器人梦想家2 小时前
具身机器人视觉服务的异步回调与并发控制
数据库·算法·机器人
我命由我123453 小时前
人脸识别 - 人脸识别选帧
java·人工智能·python·算法·安全·java-ee·人脸识别
时针滴滴答啊3 小时前
最大子数组和
算法·leetcode·职场和发展
五月底_4 小时前
LIS算法
python·算法·最长子序列
Yfhonier4 小时前
【素数定理】素数个数的位数
c++·算法·素数
学学酱快乐4 小时前
2026年PMP考试生命周期选择决策树精讲:从需求判断到混合型统一框架的应试全攻略
算法·决策树·机器学习·pmp新版考试大纲·pmp新题型·pmp培训哪家好·pmp培训机构推荐