String Matching: KMP & the Z-Function
Two linear-time matchers that beat Rabin–Karp's expected bound with a worst-case guarantee and no randomness. KMP precomputes a failure function so a mismatch slides the pattern by and the text pointer never backs up, for .
╌╌╌╌
This builds on String Matching: Naive & Rabin–Karp. There, Rabin–Karp removed the per-alignment cost — a length- comparison became a length- hash update — but its guarantee was only expected-time, and it still slid the window one position at a time with no memory of what a partial match had revealed. The two algorithms here attack the re-reading instead. Both precompute the pattern's internal self-overlap, so that after a mismatch the scan resumes exactly where the pattern's structure permits, never re-examining a text character it already knows. The payoff is a worst-case bound with no randomness at all.
Knuth–Morris–Pratt: never re-read the text
KMP attacks the redundancy directly. Suppose we are matching against and have just matched characters, , when mismatches . The naive scan would slide by one and recompare from the start. But the matched text equals , which we know completely — so we can compute, in advance and from the pattern alone, how far to slide so the next comparison resumes correctly without ever moving the text pointer backward.
The information we need is the prefix function (or failure function):
For we have : after matching the prefix
ABABA (length , index ), its longest border is ABA of length . So on a
mismatch having matched characters, instead of restarting we keep the
already-matched border ABA and resume comparing at . The
pattern effectively slides right by positions, and the
text pointer does not move.
C vs the text (highlighted). The longest border ABA realigns, sliding P right by with no rescanning of the text.Computing uses the very same self-matching idea, run on against itself. Maintain the length of the current longest border; to extend to index , follow failure links downward until or falls to .
- 1
- 2for to do
- 3while and do
- 4fall back
- 5if then
- 6extend border
- 7
- 8return
- 1
- 2chars matched so far
- 3for to do
- 4while and do
- 5mismatch: fall back
- 6if then
- 7
- 8if then
- 9report occurrence at shift
- 10allow overlapping matches
The key is that is a potential
that pays for the fallback: each unit of slide
was funded by an earlier successful character match.1 No text character
is ever examined more than a constant number of times, the central property that
the naive scan lacks.
Building the failure function by hand
Run on and watch , the length of the current longest border. Each step tries to extend the border of the previous prefix by one character; when that fails, falls back through shorter borders until one extends or none is left.
- : ; compare with — no match, and is already , so .
- : compare with — match, so
and (border
A). - : compare with — match,
, (border
AB). - : compare with — match,
, (border
ABA). - : compare with — mismatch.
Fall back: ; compare with
C— mismatch again. Fall back: ; compare withC— still no. , so . Two fallbacks, one failed extension: the cost of this step equals the border length that steps – built up. - : compare with — match, , .
The full table, read left to right: is the length of the longest border of the prefix ending at column .
ABABA has border ABA.Step shows the fallback chain in action, and the
geometry is worth drawing. Having matched the border ABA and failed to extend
it with B against C, the next candidate is not border of length
—
it is , the longest border of the border. The figure shows all
three candidates being tried against column in decreasing order:
Why is the right place to fall back to — why not some length in between? Because borders nest.
The construction's linearity is the same two-line count as the matcher's.
Across the whole run, increases only in the if (at most once per , so
at most times) and strictly decreases with every while iteration
(since ). It starts at and never goes negative, so
and the total work is at most . Step above spent two fallbacks in one step precisely because steps – had deposited three increments; the budget balances globally even though a single step can be expensive.
The matcher on a real text
Match against (), carrying from above. The variable counts matched characters:
- –:
A,B,A,B,Aall match, climbs . - : vs — mismatch. Fall back
: the border
ABAof the matchedABABAis still a live partial match, ending where we stand. Now matches , so . The text pointer never moved; was never re-read. - : matches, .
- : matches, .
- : matches, — report an occurrence
at shift (indeed ), then reset
so an overlapping occurrence starting with the final
Astays catchable. - , : and match, reaches as the text runs out.
Eleven text characters, one fallback, one report. Only was compared
against the pattern twice — once failing against C, once matching B — and
no position was touched a third time, comfortably within the comparison
budget the potential argument promises.
The Z-function: longest prefix-match at every position
The Z-function repackages the same self-similarity into a single array, and is often easier to implement bug-free.
The linear-time computation keeps a half-open window , the Z-box: the rightmost interval known to equal a prefix of (so ). For a new index :
- if , position lies inside a known prefix-match, so its mirror gives a free lower bound ;
- then extend the match character-by-character past if possible, and if the match runs beyond , slide the Z-box to the new .
- 1
- 2for to do
- 3if then
- 4copy from mirror
- 5while and do
- 6extend past the box
- 7if then
- 8advance Z-box
- 9return
The case split hides the whole efficiency argument, so make it explicit. When , the box guarantees : everything from to the box's edge is a verbatim copy of the string starting at the mirror position . Two things can happen:
- Mirror case, . The mirror's prefix-match ended strictly
inside the copied region, mismatch included: ,
and the corresponding character is still inside the box, so
it equals the mirror's and mismatches too. Hence exactly; the
whiletest fails on its first probe and the box does not move. Cost: . - Extension case, . The mirror matched at least to the box's edge, so all of matches the prefix for free — but the box says nothing about onward. Start comparing at position ; every match pushes past everything the box ever certified, and afterward the box advances to .
(When the box is useless and we are in the extension case with a free match of length .)
A full trace
Run it on (), chosen so both cases fire:
- : box empty; compare fresh: , then . , box .
- , : fresh compares fail at once (, ): .
- : fresh:
aabmatches, then . , box . - : inside the box; mirror has . Mirror case: , one failed probe, box unchanged. (Indeed , — the mirror's mismatch, replayed.)
- : mirror : mirror case again, .
- : , so outside the box: fresh compare, , .
- : fresh:
aamatches, . , box . - : inside the box; mirror . Extension case: the first character is free, and comparing at gives — a hit past the old box — then . , box advances to .
- : mirror : extension case; the probe at fails (... precisely ), so and the box stays.
- : outside the box (): fresh compare fails, .
The result is , computed with eight hits and ten misses — inside the budget with room to spare.
a matches (blue), the z fails (red), and the box advances to To match in , run the Z-function on the concatenation ,
where # is a sentinel in neither nor . Wherever inside the
portion, the prefix matches in full at that spot, so occurs in at
shift . The sentinel prevents a match from straddling the boundary
and caps . Total length is , so matching is .
What the tables give you for free
The self-overlap tables answer far more than does occur in
. Two payoffs
recur so often they are worth naming.
Periods and repetitions. A string of length has period if
wherever both are defined — equivalently, is
a border of . So the smallest period is , read straight off
the last prefix-function entry. For (), the
longest border has length (ABABA), so the smallest period is :
the string is AB repeated, plus a trailing A. From the Z-side, is a full
-fold repetition of a block of length exactly when and
. This is the whole content of Longest Happy Prefix (report the
longest border, ) and of is this string a repeated block?
.
Prefix structure and palindromes. Because is the longest prefix-match starting at , a single Z-pass over a cleverly chosen concatenation solves a family of problems: prepend the reverse of with a sentinel to test which prefixes of are palindromes (the idea behind Shortest Palindrome), or run Z on to find every occurrence with match lengths attached, which the plain boolean matcher discards.
ABABA (length 5), so period : the block `AB' tiles with one character left overChoosing a matcher
Across both string-matching lessons there are four correct algorithms; the choice is about constants, guarantees, and what else the problem asks for.
- Naive wins more often than its worst case suggests. For or so, or for a one-off search in text without heavy repetition, the expected cost is with tiny constants and zero preprocessing. Reject it only when the input may be adversarial or repetitive.
- Rabin–Karp is the only one that generalizes cheaply to many patterns at once and to numeric or 2-D fingerprinting; its guarantee is expected-time only, and soundness depends on the verify step.
- KMP gives the worst-case bound with no randomness, and its scan is online: it reads strictly left to right, one character at a time, keeping only and the table between characters. That makes it suitable for streams too large to store and the conceptual basis for matching automata (Aho–Corasick is KMP's failure idea on a trie of many patterns).
- Z matches KMP's guarantee when the whole input can be concatenated up front, and the array it produces is often the main value: periods, borders, and prefix structure read straight off it. Many string exercises reduce to one Z-pass plus a scan.
To summarize both lessons: naive re-derives information it already had; hashing compresses a window to a comparable summary; and precompute the pattern's self-overlap so no information is ever re-derived. The next lesson pushes the same idea further, preprocessing the text itself into suffix arrays so that many queries against one text each cost near nothing.
The string-matching lineage and periodicity theory
KMP is named for the 1977 paper of Knuth, Morris, and Pratt (Fast Pattern
Matching in Strings, SIAM J. Comput.), the result that first broke the
barrier for exact matching in the worst case; Morris and Pratt had the linear
matcher and Knuth supplied the analysis connecting it to the theory of periods.
The Boyer–Moore algorithm (Boyer & Moore, A Fast String Searching
Algorithm, CACM 1977), published the same year, attacks the problem from the
opposite end — it matches the pattern right to left and uses a bad character
rule to skip ahead by more than one position, so on typical text it examines
sublinear in characters and is what grep and many memmem
implementations actually use.
The prefix-function / period machinery is also the gateway to the deeper theory of string periodicity. The Fine–Wilf theorem (Fine & Wilf, 1965) states that if a string of length has two periods and with , then it also has period — the structural fact behind the nesting of border chains, and the reason KMP's fallback is well-defined. The same periodicity theory drives modern results such as constant-space and packed string matching, and the failure-link idea generalizes directly to the Aho–Corasick automaton for many patterns and to suffix automata for indexing a text.
The Z-function, by contrast, is folklore rather than a single named paper — it is
the -algorithm
of the competitive-programming and stringology literature
(Gusfield's Algorithms on Strings, Trees, and Sequences, 1997, presents it as
the fundamental preprocessing tool and derives KMP, Boyer–Moore, and more from
it). Its appeal is pedagogical and practical in equal measure: one short,
hard-to-get-wrong loop that exposes a string's entire prefix structure, from
which periods, borders, and many matching problems fall out by a single scan.
Takeaways
- KMP precomputes the prefix/failure function , so on a mismatch the pattern slides by and the text pointer never backs up: worst-case , justified by an amortised potential argument on .
- The failure array is built by the same two-pointer self-matching, in ; its correctness rests on the fact that a string's borders nest, so the fallback chain enumerates every candidate in decreasing order.
- The Z-function computes the longest prefix-match at every position in via the Z-box; running it on and finding matches in .
- and are interconvertible — two encodings of a string's self-similarity — and both give periods for free: the smallest period is .
- KMP/Z give worst-case guarantees with no randomness; Rabin–Karp trades that for simplicity and multi-pattern flexibility. KMP's online scan handles unbounded streams.
Footnotes
╌╌ END ╌╌