Suppose you have a pattern pat and a long text txt, and you want to know every position where pat appears. The naive approach re-reads the pattern from scratch at each position — comparisons and painfully slow on repetitive data.
The Z-algorithm, introduced as part of the classical string-algorithm canon (Gusfield's 1997 textbook gives the cleanest exposition), takes a completely different view. Concatenate the pattern and text with a sentinel that does not appear in either — Z-string = pat + '$' + txt — and build the Z-array: for every index , Z[i] is the length of the longest substring starting at that also matches a prefix of the full Z-string.
Once you have the Z-array, finding every match is trivial: any position (inside the text portion) where Z[i] equals the length of the pattern is exactly a match. The entire computation — building the array and scanning for matches — runs in time with extra space and no hash tables.
The key insight that keeps the algorithm linear is the Z-box: the algorithm maintains the rightmost interval [l, r] where a prefix match is already known. When processing position , it can initialize Z[i] from a previously computed value Z[i-l] instead of comparing from scratch. Each character is examined at most twice: once when it extends the Z-box to the right, and possibly once more to verify the new boundary. The total comparison count is .
This is in the same family as KMP pattern matching — both solve the problem in linear time — but the Z-array is often easier to implement from scratch and reasons more explicitly about prefix structure.
Comments
Loading comments...