算法学习-exKMP
什么是 exKMP
exKMP(Z-Algorithm) 是一个可以以 \(O(|S|+|T|)\) 的时间复杂度求出
- \(T\) 串的每个后缀与 \(T\) 的 LCP(最长公共前缀)
- \(T\) 串和 \(S\) 串每个后缀的 LCP。
的算法。
算法过程
首先回忆一下 KMP 算法,求 \(nxt\) 数组和两串匹配本质上没啥区别。
所以我们尝试也将上述俩问题,即 \(T-T\) 和 \(T-S\) 变成一个问题。
先解决第一个问题:令 \(z_x\) 为 \(\max\limits_{i=1}^{ |T| - x + 1}\{T_{1\sim i}=T_{x\sim x + i - 1}\}\),那么答案就是 \(z\) 数组。
如何求出?
先看下图:令 \(L\) 为满足 \(k+Z_k-1=\max\limits_{j=1}^{i-1}j+Z_j-1\) 的 \(k\)。
根据 \(z\) 的定义,我们有 \(T_{1\sim Z_L}=T_{L\sim L+Z_L-1}\land T_{Z_L+1}\neq T_{L+Z_L}\)
所以有 \(T_{i\sim L+Z_L-1}=T_{i-L+1\sim Z_L}\)
再根据 \(z\) 的定义,有 \(T_{1\sim Z_{i-L+1}}=T_{i-L+1\sim i-L+1+Z_{i-L+1}-1}\)
这时候有两种情况:
-
\(Z_{i-L+1}\le R-i+1\),显然 \(Z_i=Z_{i-L+1}\)。
-
\(Z_{i-L+1}>R-i+1\),那么因为 \(Z_i\) 最多也就是 \(R-i+1\)(因为 \(T_{L+Z_L-i+1}=T_{Z_L+1}\neq T_{L+Z_L}\)),所以 \(Z_i=R-i+1\)
所以有 \(Z_i=\min(R-i+1,Z_{i-L+1})\)。
但是,上述的计算都是基于 \(R\ge i\) 来说的。
否则呢?
直接暴力匹配即可。
时间复杂度呢?
注意到暴力匹配的字符的 \(z\) 和一定不超过 \(n\) (因为 \(z\) 匹配到哪,下一次至少从那开始暴力匹配),所以仍为线性的。
然后 \(T-S\) 的思路和上面的 \(T-T\) 是一样的,不再赘述。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e7 + 5;
char s[N], t[N];
int z[N], p[N], n, m;
signed main()
{
ios::sync_with_stdio(0);cin.tie(0);
cin >> s + 1 >> t + 1;
n = strlen(s + 1);
m = strlen(t + 1);
z[1] = m;
int l = 0, r = 0;
for(int i = 2; i <= m; i ++)
{
if(r >= i) z[i] = min(r - i + 1, z[i - l + 1]);
while(t[z[i] + 1] == t[i + z[i]] && i + z[i] <= m) z[i] ++;
if(i + z[i] - 1 > r) l = i, r = i + z[i] - 1;
}
l = r = 0;
for(int i = 1; i <= n; i ++)
{
if(r >= i) p[i] = min(r - i + 1, z[i - l + 1]);
while(t[p[i] + 1] == s[i + p[i]] && i + p[i] <= n) p[i] ++;
if(i + p[i] - 1 > r) l = i, r = i + p[i] - 1;
}
return 0;
}
作者:adam01
出处:https://www.cnblogs.com/adam01/p/17649581.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】