= the length of the longest common prefix of and the suffix . By convention (or 0; be consistent).

s = a a b c a a b x a a a z
z = _ 1 0 0 3 1 0 0 2 2 1 0

Computation —

Maintain the Z-box : the rightmost interval known to match a prefix of .

vector<int> zFunction(const string& s) {
    int n = s.size();
    vector<int> z(n, 0);
    z[0] = n;
    for (int i = 1, l = 0, r = 0; i < n; i++) {
        if (i < r) z[i] = min(r - i, z[i - l]);        // reuse previous work
        while (i + z[i] < n && s[z[i]] == s[i + z[i]]) z[i]++;
        if (i + z[i] > r) { l = i; r = i + z[i]; }     // extend the Z-box
    }
    return z;
}

Why linear: the while loop only runs when it pushes further right, and never decreases — so the total number of character comparisons is .

Why min(r - i, z[i - l]): inside the Z-box, equals , so starts at — capped at , because beyond nothing is known yet.

Pattern matching

vector<int> findAll(const string& text, const string& pat) {
    string s = pat + '\x01' + text;
    vector<int> z = zFunction(s), res;
    for (int i = pat.size() + 1; i < (int)s.size(); i++)
        if (z[i] >= (int)pat.size())
            res.push_back(i - pat.size() - 1);
    return res;
}

time and memory. The separator must not appear in either string.

What the Z-function answers

QuestionMethod
All occurrences of a patternas above
Number of distinct substringsadd characters one at a time, using of the reversed prefix
Longest common prefix of and of
Is a rotation of ?search in
Smallest periodsmallest with
Compare with one query plus one character
String compression / repeated blockscheck with and

Counting distinct substrings incrementally

Adding a character to the end of creates new substrings (the suffixes of the new string), minus those that already occurred. Computing the Z-function of the reversed new string gives , the length of the longest new suffix that already appeared, so the count increases by . Total — good enough when and much simpler than a suffix structure.

Z-function vs prefix function

They are interconvertible in and both solve matching in linear time. Practical differences:

Z-functionPrefix function
MeaningLCP with the whole stringlongest border of a prefix
Easier to derive from scratch
Extends to an automaton
Extends to multi-pattern
Gives periods directlyneeds a scan✔ immediately

Use the Z-function for matching and comparison; the prefix function when you need borders, periods, or an automaton to run a DP over.

The Z-box idea generalises

“Maintain the rightmost known-matching interval and reuse it” is exactly the technique behind Manacher’s algorithm for palindromes. Recognising the shared skeleton makes both easier to remember: keep an interval, reuse the mirrored answer, extend naively only past the boundary.

See also: Prefix Function · Z-Algorithm · Manacher