The Z-algorithm computes the Z array full
This proof shows: correctness, termination.
Claim. For a string S[0…N−1], Z-ARRAY(S) stops and returns Z with Z[0]=N and, for 1≤k<N, Z[k]=lcp(S,S[k…N−1]), the length of the longest common prefix. Z-MATCH(T,P) outputs exactly the valid shifts in increasing order.
Termination. The loop of line L2 runs N−1 times. In the loop of lines L4 and L5, k+Z[k] increases at each pass and is at most N, so the loop stops.
Invariant. At the start of the iteration for k:
(I) Z[j]=lcp(S,S[j…]) for 1≤j<k; r=max({0}∪{j+Z[j]:1≤j<k}); and if r>0 then 1≤l<k, r=l+Z[l].
It holds for k=1 with l=r=0. From (I) with r>0, S[l…r−1]=S[0…r−l−1] by the definition of Z[l].
Lemma. Let z∗=lcp(S,S[k…]) and let z0 be the value set by line L3. Then z0≤z∗, and if z0<r−k then z0=z∗.
Proof. If k≥r, z0=0≤z∗, and the second part is empty since r−k≤0. Let k<r, so l<k<r, and let k′=k−l≥1. The box gives S[k…r−1]=S[k′…r−l−1], a string of length r−k.
First, z0≤z∗. Since k′<k, Z[k′]=lcp(S,S[k′…]) by (I). With z0=min(r−k,Z[k′]), for i<z0 we have S[i]=S[k′+i] (as i<Z[k′]) and S[k′+i]=S[k+i] (as i<r−k, inside the box). So S[0…z0−1]=S[k…k+z0−1].
Second, assume z0<r−k, so z0=Z[k′]<r−k. Then k′+Z[k′]<r−l≤N, so the character S[k′+Z[k′]] exists, and it differs from S[Z[k′]] by maximality of Z[k′]. Since Z[k′]<r−k, the box gives S[k+Z[k′]]=S[k′+Z[k′]]=S[Z[k′]]. So the match at k stops at Z[k′] and z∗=z0. □
Step. By the lemma, z0≤z∗, and S[0…z0−1]=S[k…k+z0−1]. The loop of lines L4 and L5 keeps S[0…Z[k]−1]=S[k…k+Z[k]−1] and stops at the first Z[k]≥z0 where k+Z[k]=N or S[Z[k]]=S[k+Z[k]], which is z∗. Line L6 updates r to max(r,k+Z[k]) with l=k when r changes, so (I) holds for k+1. At the end, (I) for k=N gives every value, and Z[0]=N by line L1.
Matching. Let S=P$T with ∣S∣=m+1+n and m≥1, and let 0≤s≤n−m. Position m+1+s holds T[s]. Because $ equals no character of P or T, the common prefix of S and S[m+1+s…] cannot include S[m]=$ matched against a character of T, so Z[m+1+s]≤m, and Z[m+1+s]=m exactly when T[s…s+m−1]=P. Line L11 visits the shifts in increasing order, and none when m>n. For m=0, line L9 outputs all shifts 0,…,n, which are all valid. ■