String matching
Given a text T of length n and a pattern P of length m, find every position where P occurs in T. This is what "Find" in an editor does, and what tools like grep and DNA-sequence searches are built on.
The naive method tries every shift s and compares P with T[s..s+m−1] character by character. On a mismatch it moves the pattern one place to the right and starts over from its first character. It forgets everything it just learned, so on inputs like T = AAAAAAAAAB, P = AAAB it makes about nm comparisons.
The KMP idea
Suppose the first j pattern characters matched and then a mismatch happened. We already know the last j text characters: they are P[0..j−1]. The next shift that could possibly work lines up a prefix of the pattern with the end of those j characters. So the question "how far can we slide?" depends only on the pattern, and can be answered in advance.
The failure table (also called the prefix function) stores the answer: fail[j] is the length of the longest proper prefix of P[0..j] that is also a suffix of it. For P = ABABCABAB:
j 0 1 2 3 4 5 6 7 8 P[j] A B A B C A B A B fail[j] 0 0 1 2 0 1 2 3 4 (fail[3] = 2: "AB" is both a prefix and a suffix of "ABAB")
After a mismatch with j characters matched, KMP sets j = fail[j-1]: it slides the pattern so that the longest possible prefix is still matched, and compares the same text character again. The text position i never moves backwards.
kmpSearch(T, P):
j = 0 // characters of P matched
for i = 0 to n − 1:
while j > 0 and T[i] ≠ P[j]:
j = fail[j − 1] // slide the pattern
if T[i] == P[j]:
j = j + 1
if j == m:
report a match at i − m + 1
j = fail[m − 1] // keep looking (matches may overlap)
Building the failure table
The table is built by running the same idea on the pattern itself. Keep len, the length of the prefix matched so far. When P[i] == P[len], the prefix grows by one: fail[i] = len + 1. When they differ, fall back to the next shorter candidate, len = fail[len-1], and try again. When len is already 0, fail[i] = 0. In the animation, P[i] is outlined and P[len] is blue.
Running time
Each comparison either moves i forward or slides the pattern forward, and neither can happen more than n times. So the search makes at most 2n comparisons, and building the table at most 2m: O(n + m) in total, compared with O(nm) for the naive method. At the end, the animation shows both comparison counts for your input. Try a repetitive text such as AAAAAAAAAAAAAAAAAAAAB with the pattern AAAAB to see the difference.
Worked example
Pattern P = ABABC. Its failure table: fail[2] = 1 because "A" is both a prefix and a suffix of "ABA", fail[3] = 2 because of "AB" in "ABAB", and fail[4] = 0 because nothing ending in C is a prefix.
j 0 1 2 3 4 P[j] A B A B C fail[j] 0 0 1 2 0
Now search the text T = ABABABC:
i=0..3 T[0..3] = ABAB matches P[0..3] j = 4 (4 comparisons)
i=4 T[4] = A ≠ P[4] = C: mismatch with 4 matched
slide: j = fail[3] = 2 ("AB" still matched), compare T[4] with P[2] = A: match, j = 3
i=5 T[5] = B = P[3] j = 4
i=6 T[6] = C = P[4] j = 5 = m: match at 6 − 5 + 1 = 2
KMP makes 8 comparisons and never looks at a text character before position 4 again. The naive method compares ABABC with ABABA (5 comparisons), then with BABAB (1), then with ABABC (5): 11 comparisons. On a long, repetitive text the difference grows to n + m against nm.
Common mistakes
- "Proper" prefix:
fail[j]is the longest prefix ofP[0..j]that is also a suffix but not the whole string. Otherwise every value would bej + 1and the pattern would never slide. - Do not advance i after a fallback. After
j = fail[j-1], the same text character is compared again with the newP[j]; only a match orj == 0moves on. - After a full match, continue with
j = fail[m-1], notj = 0, or overlapping matches are missed: inAAAAthe patternAAoccurs at 0, 1 and 2. - Some books store the table shifted by one (
π[0] = −1); the idea is the same, only the indices change.
Rabin-Karp takes another route, comparing window hashes first: see Rabin-Karp.
To search one text for many patterns, preprocess the text instead: see Suffix Array, where every query is a binary search.
KMP's table is a DFA for one fixed pattern; Regex to NFA to DFA builds a DFA for any regular expression.
See Aho-Corasick, which runs the KMP failure idea on a trie of many patterns.
What the page leaves out
Large alphabets and Unicode, where a "character" may be several bytes or code points; searching for many patterns at once (Aho–Corasick); faster practical matchers such as Boyer–Moore, Horspool and the vectorised memchr-based searches in real libraries; and streaming text that arrives in chunks, where KMP's state between chunks is just the number of characters matched.