Z-Algorithm详解
0.前言
给你一个文本串 t t t和一个模式串 p p p,让你寻找 p p p在 t t t中出现的所有位置。
例如, t = " a b a c a b a b a c " t="abacababac" t="abacababac", p = " a b a " p="aba" p="aba",那么 p p p在 t t t中出现了 3 3 3次,起始位置分别是 1 1 1, 5 5 5, 7 7 7。
很显然可以想到 O ( ∣ t ∣ ∗ ∣ p ∣ ) O(|t|*|p|) O(∣t∣∗∣p∣)的暴力算法,但是如果 t t t和 p p p的长度都是 1 0 5 10^5 105级别的就会超时,我们需要更高效的方法,这里我给大家讲一下 Z Z Z算法。
1.一些函数的定义
我们定义 z i ( s ) z_i(s) zi(s)为对于所有的 2 ≤ i ≤ ∣ s ∣ 2 \leq i \leq |s| 2≤i≤∣s∣,以 i i i开头的子串和 s s s的最长公共前缀的长度
如:
s = " a b a " s="aba" s="aba",那么 z 3 ( s ) = 1 z_3(s)=1 z3(s)=1(以 3 3 3为起始位置,能够匹配 s s s长度为 1 1 1的前缀 " a " "a" "a",但匹配不了长度为 2 2 2的前缀 " a b " "ab" "ab")。
s = " a b c a b c a b " s="abcabcab" s="abcabcab",那么 z 4 ( s ) = 5 z_4(s)=5 z4(s)=5
s = " a b a c a b a b a c a " s="abacababaca" s="abacababaca",那么 z 5 ( s ) = 3 , z 7 ( s ) = 5 z_5(s)=3, z_7(s)=5 z5(s)=3,z7(s)=5
2.如果已知 z i z_i zi的值如何求出答案
我们将 p p p粘在 s s s的前面,中间用一个字符(如下划线)隔开,可以得到一个字符串 s s s。我们假设我们已经知道了所有 z i ( s ) z_i(s) zi(s)的值,那么怎么求出答案呢。
我们可以扫描 s s s串中从 ∣ p ∣ + 2 |p|+2