后缀数组求 LCP 和相关证明

后缀数组求 LCP 和相关证明

一些定义

SA(i) 排名为 i 的后缀左端点;rank(i) 左端点为 i 的后缀排名;suf(i) 左端点为 i 的后缀;

lcp(S,T),串 ST 的最长公共前缀,即 max{x|yx,Sy=Sy}

LCP(i,j),排名为 i 的后缀和排名为 j 的后缀的最长公共前缀,即 lcp(suf(SA(i)),suf(SA(j)))

height(i),排名为 ii1 的后缀的最长公共前缀,即 LCP(i,i1),特别地 height(1)=0

h(i)=height(rank(i))

性质1

对于 1in,显然有:

LCP(i,i)=nSA(i)+1

LCP(i,j)=LCP(j,i)

定理 1

对于 1i<jn,有:

LCP(i,j)=mini<kj{LCP(k,k1)}

证明:


引理

对于 1i<jn,有:

LCP(i,j)=min{LCP(i,k),LCP(k,j)} (ikj)

证明:

min{LCP(i,k),LCP(k,j)}=p

LCP(i,k)p,LCP(k+1,j)p

所以 ik 至少有前 p 位相等,kj 至少有前 p 位相等,

所以 LCP(i,j)p

又因为minLCP(i,k),LCP(k,j)=p

suf(i)=a,suf(k)=b,suf(j)=c

则有 ap+1bp+1bp+1cp+1

ap+1bp+1bp+1cp+1 中仅有一个成立,显然有 ap+1cp+1

又根据 i,j,k 的排名关系,有 ap+1bp+1cp+1

ap+1bp+1bp+1cp+1 均成立,假设 ap+1=cp+1

则有 ap+1=bp+1=cp+1,与条件矛盾,假设不成立,则 ap+1cp+1

综上有 ap+1cp+1,所以 LCP(i,j)p

结合 LCP(i,j)p,有 LCP(i,j)=p=min{LCP(i,k),LCP(k,j)},得证。


根据引理,可推出:

LCP(i,j)=min{LCP(i,k),LCP(k,j)}

LCP(i,j)=min{LCP(i,i+1),LCP(i+1,j)}

LCP(i,j)=min{LCP(i,i+1),min{LCP(i+1,i+2),LCP(i+2,j)}}

归纳可得:

LCP(i,j)=mini<kj{LCP(k,k1)}

得证。

转化

LCP(i,j)=mini<kj{LCP(k,k1)}=mini<kj{heightk}

这样 LCP 问题就转化为区间最值(RMQ)问题,可以使用 STO(nlogn) 预处理 O(1) 查询。

现在的问题就转化为了求 height 数组。

定理 2

对于 1<in,有:

h(i)h(i1)1

证明:


性质2

对于 1i,j<n,lcp(suf(i),suf(j))>1,有:

suf(i)<suf(j)suf(i+1)<suf(j+1)

lcp(suf(i),suf(j))1=lcp(suf(i+1),suf(j+1))


定理 1 的引理的推论

对于 1i,jn,有:

LCP(i,j)LCP(k,j) (ikj)

证明:根据定理 1 的引理,显然成立。


h(i1)1 时,h(i)0h(i1)1,得证;

h(i1)>1 时,即 height(rank(i1))>1

可推出 rank(i1)>1,因为 height(1)=0

j=i1k=SA(rank(j)1),有:

h(i1)=LCP(rank(j),rank(k))=lcp(suf(j),suf(k))

suf(k)<suf(j)

因为 lcp(suf(j),suf(k))=h(i1)>1,根据性质2有:

h(i1)1=lcp(suf(i),suf(k+1))

suf(k+1)<suf(i)

rank(k+1)<rank(i)rank(k+1)rank(i)1

根据定理 1 的引理的推论得:

(1)LCP(rank(i)1,rank(i))LCP(rank(k+1),rank(i))(2)=lcp(suf(i),suf(k+1))(3)=h(i1)1

又因为 LCP(rank(i)1,rank(i))=h(i),所以 h(i)h(i1)1,得证。

具体求法

有了定理 2 后,就可求出 height 数组。

先考虑暴力的代码,即从头开始暴力匹配,时间复杂度 O(n2)

根据定理 2,h(i)h(i1)1,可以直接从 h(i1)1 开始匹配。

因为 h(i)n,每次 h(i) 最多减一,所以时间复杂度 O(n)

代码

void get_height() {
	for (int i = 1, k = 0, j; i <= n; i ++) {
		if (rk[i] == 1) continue; // height[1]=0
		k = k ? k - 1 : k; // h[i-1]-1
		for (j = sa[rk[i] - 1]; 
			i + k <= n && j + k <= n 
			&& S[i + k] == S[j + k]; k ++);
		height[rk[i]] = k; // k=h[i]=height[rk[i]]
	}
}
posted @   maniubi  阅读(23)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示