Knuth–Morris–Pratt (KMP)
Linear-time pattern matching that never re-reads text characters, using a precomputed failure (LPS) table of the pattern.
Overview
KMP finds all occurrences of a pattern p in a text t in O(n + m) time. The idea is that when a comparison fails after matching j characters, those j characters are already known — they are p[0..j-1] — so the pattern can be shifted by an amount computed purely from the pattern itself, without re-examining the text.
The precomputation is the failure function, usually stored as an array lps (longest proper prefix which is also a suffix). lps[i] is the length of the longest border of p[0..i]: a string that is both a proper prefix and a proper suffix. Borders are the key to safe shifting.
Intuition
A mental model before the formal terms.
Suppose you have matched "aabaa" and the next text character breaks the match. A naive matcher slides one step and starts over. But look at "aabaa": its last two characters "aa" are also its first two. So if you slide the pattern so that its first "aa" sits where the last "aa" was, the first two characters are guaranteed to match already — you can continue comparing from p[2] instead of p[0]. The LPS array records, for every possible match length, exactly how much of the match survives the slide.
Worked example, p = "aabaaab": lps = [0, 1, 0, 1, 2, 2, 3]. lps[1] = 1 because "aa" has border "a". lps[2] = 0 because "aab" has none. lps[4] = 2 because "aabaa" has border "aa". At i = 5 ("aabaaa") the candidate is to extend the previous border of length 2 with p[2] = 'b', but p[5] = 'a' ≠ 'b', so we fall back to lps[1] = 1 and try p[1] = 'a': it matches, giving lps[5] = 2 (border "aa"). At i = 6, p[2] = 'b' equals p[6] = 'b', so lps[6] = 3 (border "aab").
How it works
- Build
lpsfor the pattern. Keeplen= length of the current border ofp[0..i-1]. To extend top[0..i]: ifp[i] == p[len], setlps[i] = len + 1. Otherwise, iflen > 0, fall back tolen = lps[len - 1]and retry (the next-shorter border); iflen == 0, setlps[i] = 0. - Search: keep
j= number of pattern characters matched so far. For each text charactert[i]: whilej > 0andt[i] != p[j], setj = lps[j - 1]. Then ift[i] == p[j], incrementj. - When
j == m, report a match starting ati - m + 1and setj = lps[m - 1]so overlapping matches are still found. - The text index
ionly ever moves forward; the fallback loop shrinksj, which was increased at most once per text character, so the total work isO(n).
Why it works
If p[0..j-1] matched the text ending at position i - 1 and p[j] mismatches, then any occurrence starting between the old start and i must align a prefix of p with a suffix of the already-matched p[0..j-1] — i.e. with a border. The longest such border is lps[j-1], and any shorter border is reached by iterating lps further. Skipping directly to the longest border never skips a real match.
The lps computation is correct because the borders of p[0..i] are exactly the borders of p[0..i-1] extended by one character when p[i] matches, and every border of p[0..i-1] is either the longest one or a border of that longest one, so the chain len → lps[len-1] → … enumerates all candidates in decreasing length.
Amortised analysis: j (or len) increases by at most 1 per iteration and never goes below 0, so the total number of decreases across the whole run is bounded by the number of increases, giving O(n + m) overall.
Recognition
How to tell a problem wants this.
- The problem mentions prefix that is also a suffix, borders, periods of a string, or "shortest palindrome by prepending".
- Pattern matching with guaranteed linear time, or inputs that are highly repetitive (DNA, binary).
- Finding the smallest repeating unit:
n - lps[n-1]is the period if it dividesn.
Interactive visualization
Play, step, change the input. ← → and space work too.
1lps = [0]*m; len = 02for i in 1 .. m-1:3 while len > 0 and pattern[i] != pattern[len]: len = lps[len-1]4 if pattern[i] == pattern[len]: len += 15 lps[i] = len6i = j = 07while i < n:8 if text[i] == pattern[j]: i += 1; j += 19 if j == m: report match at i-m; j = lps[j-1]10 else if j > 0: j = lps[j-1] # fall back, keep i11 else: i += 1Pseudocode
1lps[0] = 0, len = 02for i in 1 .. m-1:3 while len > 0 and p[i] != p[len]: len = lps[len-1]4 if p[i] == p[len]: len += 15 lps[i] = len6j = 07for i in 0 .. n-1:8 while j > 0 and t[i] != p[j]: j = lps[j-1]9 if t[i] == p[j]: j += 110 if j == m: report i - m + 1; j = lps[m-1]Implementations
11 · Build the LPS (failure) table2def build_lps(p: str) -> list[int]:3 m = len(p)4 lps = [0] * m5 length = 0 # length of the current border of p[0..i-1]6 for i in range(1, m):72 · Fall back to shorter borders on mismatch8 while length > 0 and p[i] != p[length]:9 length = lps[length - 1]10 if p[i] == p[length]:11 length += 112 lps[i] = length13 return lps14 15 16def kmp_search(text: str, pattern: str) -> list[int]:173 · Scan the text with the automaton18 n, m = len(text), len(pattern)19 if m == 0:20 return list(range(n + 1))21 lps = build_lps(pattern)22 matches: list[int] = []23 j = 0 # characters of pattern matched so far24 for i, ch in enumerate(text):25 while j > 0 and ch != pattern[j]:26 j = lps[j - 1]27 if ch == pattern[j]:28 j += 1294 · Report a match and keep going for overlaps30 if j == m:31 matches.append(i - m + 1)32 j = lps[m - 1]33 return matcheslps = [0] * mbuilds the failure table;lps[0]is always 0 because a one-character prefix has no proper border.- The variable is named
lengthrather thanlento avoid shadowing the built-inlen(). for i, ch in enumerate(text)yields the index and character together, sotext[i]is not re-indexed in the fallback loop.- The
while j > 0 and ch != pattern[j]loop follows the border chain;jshrinks butinever moves back. j = lps[m - 1]after each report keeps overlapping matches.
Pure-Python loops are slow; for a one-off search str.find (C implementation) wins. KMP in Python is worth it for the LPS table itself.
- Python strings are immutable and compare single characters as small string objects; the interpreter caches one-character Latin-1 strings, so
p[i] != p[length]does not allocate. enumerateis the idiomatic way to walk index and value; avoidrange(len(text))plustext[i]when both are needed.- Typing
list[int](PEP 585, Python 3.9+) needs no import fromtyping.
- Naming the border length
lenand then callinglen(p)later in the same scope —TypeError: int is not callable. - Using
ifin place ofwhilefor the fallback. - Resetting
j = 0after a match instead ofj = lps[m - 1].
- Character comparison: C++ compares
charbytes, JS/TS compare UTF-16 code units (charCodeAt), Python compares Unicode code points — results agree for ASCII, differ for non-BMP characters. - Python and JS/TS strings are immutable; C++
std::stringis mutable but KMP never needs to modify either input. - Only the pattern must be in memory: in all four languages the text loop can be fed from a stream one character at a time.
- The failure table is a small-integer array:
std::vector<int>in C++, packed SMI array in JS/TS, list ofintin Python.
Complexity
Text is read strictly left to right, once — KMP works on streams.
Compare growth rates in the Complexity Explorer →When to use — and when not to
- Guaranteed linear-time single-pattern search, especially on repetitive input.
- Streaming text where you cannot back up (only the pattern is preprocessed).
- Any question about borders or periods of a string: shortest repeating unit, shortest palindrome by prepending, longest prefix-suffix.
- Searching many patterns at once — build Aho–Corasick instead.
- Many queries on one fixed text — Suffix Array preprocesses the text once.
- Short patterns on natural-language text, where Naive String Matching is simpler and about as fast.
Alternatives
Common mistakes
- Computing
lps[i]as "longest prefix that equals a suffix" without the proper restriction — the whole string is trivially both, solps[i]would bei + 1. - Using
ifinstead ofwhilefor the fallbacklen = lps[len - 1]— one fallback is not always enough (see thei = 5step in"aabaaab"). - After a full match, resetting
j = 0instead ofj = lps[m - 1], which misses overlapping occurrences. - Off-by-one in the reported start index: it is
i - m + 1, noti - m.
Interview patterns
- Implement
strStrin linear time. - Shortest palindrome: build
lpsofs + "#" + reverse(s)to find the longest palindromic prefix. - Repeated substring pattern:
sis periodic iffn % (n - lps[n-1]) == 0andlps[n-1] > 0. - Count occurrences of each prefix of
sinsusing the prefix function.
- Recognizing the approach from an array and a targetIntermediate
- Deciding whether O(n²) can be improvedIntermediate
- Recognizing a sliding-window problemIntermediate
- Minimum Size Subarray SumIntermediate
- Longest Substring Without Repeating CharactersIntermediate