KMP algorithm — failure function, O(n+m) — full derivation
WHAT problem are we solving?
WHAT: Find all occurrences of a pattern (length ) inside a text (length ).
WHY naive is slow: Naive matching compares at every shift. On adversarial input like , it does work, re-scanning the same text characters again and again.
HOW KMP wins: The text pointer only ever moves forward. When a mismatch happens at pattern position , instead of resetting , we set — jumping the pattern to its longest reusable prefix. Each text char is "examined" amortized times → .
The failure function (the whole trick)
Worked: build for ababaca
| i | char | S[0..i] | longest proper prefix=suffix | π[i] |
|---|---|---|---|---|
| 0 | a | a | (none) | 0 |
| 1 | b | ab | (none) | 0 |
| 2 | a | aba | a |
1 |
| 3 | b | abab | ab |
2 |
| 4 | a | ababa | aba |
3 |
| 5 | c | ababac | (none) | 0 |
| 6 | a | ababaca | a |
1 |
Why π[4]=3? ababa: prefix aba = suffix aba. Longer (abab) is not a
suffix. So 3.
Why π[5]=0? ababac ends in c; no prefix of ababac ends in c except the
whole thing (not proper). So 0.
DERIVING the -computation algorithm from scratch
We build incrementally. Assume we know and want . Let = length of the best prefix-suffix for the previous position.
Case 1 — we can extend. If , then the prefix S[0..j-1] that was a
suffix can grow by one char on both ends. So .
Why this step? A border (prefix=suffix) of length for S[0..i-1], plus one
matching char, gives a border of length for S[0..i].
Case 2 — mismatch, fall back. If and , the next-best candidate border length is . We set and retry.
Why ? The longest border shorter than that is also a border of the current prefix is exactly the longest border of that border — which is . This recursion walks down the chain of nested borders.
Case 3 — bottomed out. If and still mismatch, .
pi[0] = 0
for i = 1 .. m-1:
j = pi[i-1]
while j > 0 and S[i] != S[j]:
j = pi[j-1] # fall back along border chain
if S[i] == S[j]:
j += 1
pi[i] = j
DERIVING the matching loop
Run the same machine over the text. Let index , index .
j = 0
for i = 0 .. n-1:
while j > 0 and T[i] != P[j]:
j = pi[j-1] # mismatch → slide pattern, keep i
if T[i] == P[j]:
j += 1
if j == m: # full match ending at i
report match at i-m+1
j = pi[j-1] # continue searching for overlapping matchesWhy don't we move i back on mismatch? Because the prefix P[0..π[j-1]-1] is
guaranteed equal to the text already scanned. Re-reading would re-confirm a
known equality. So marches forward only.
WHY it is O(n+m) — the amortized proof
This is the key insight that separates KMP from naive: the amortized cost of the fallback is bounded by how much ever grew.
Full match example: abab, ababaababab
First for abab: [0,0,1,2].
| i (text) | T[i] | j before | action | j after |
|---|---|---|---|---|
| 0 | a | 0 | match | 1 |
| 1 | b | 1 | match | 2 |
| 2 | a | 2 | match | 3 |
| 3 | b | 3 | match → j=4=m, report 0, j=π[3]=2 | 2 |
| 4 | a | 2 | match | 3 |
| 5 | a | 3 | mismatch (P[3]=b≠a) j=π[2]=1; P[1]=b≠a j=π[0]=0; P[0]=a==a | 1 |
| 6 | b | 1 | match | 2 |
| 7 | a | 2 | match | 3 |
| 8 | b | 3 | match → j=4, report 6, j=2 | 2 |
| 9 | a | 2 | match | 3 |
| 10 | b | 3 | match → j=4, report 7, j=2 | 2 |
Why report 0 then 6 then 7? Overlapping occurrences abab at indices 0, 6, 7.
At i=5 the fallback from j=3 to 1 reused the matched a instead of restarting.
Recall Feynman: explain to a 12-year-old
Imagine you're matching a word letter by letter and you mess up on the 5th letter. A dumb robot would go all the way back and start the whole word over. A smart robot remembers: "the last few letters I just typed are the same as the start of my word!" So it doesn't restart — it pretends it already typed the beginning and continues. The "failure function" is just a cheat-sheet that tells the robot, for every spot, how many letters it gets to keep when it slips up. Because it never re-reads the book, it's super fast.
Active Recall
What does the failure function π[i] store?
Why must the prefix in π be proper (strictly shorter)?
On a mismatch at pattern index j, what do we set j to?
After a full match (j==m), why set j=π[m-1] instead of 0?
Why is KMP matching O(n+m)?
Build π for "ababaca".
What is the recurrence when S[i]==S[π[i-1]]?
Why does the text pointer i never move backward in KMP?
Connections
- Z-algorithm — alternative linear string matching via Z-array
- Rabin-Karp — hashing-based matching, expected
- Aho-Corasick — generalizes KMP failure links to many patterns (a trie of fail links)
- Suffix Automaton & Suffix Array — heavier structures for repeated queries
- Amortized Analysis — the potential argument used for the bound
- Borders and Periods of Strings — gives the smallest period of
Concept Map
Hinglish (regional understanding)
Intuition Hinglish mein samjho
Dekho, KMP ka core idea bohot simple hai. Jab tum pattern ko text se match kar rahe ho aur beech me ek character mismatch ho jaata hai, toh naive algorithm pura kaam phenk ke pattern ko sirf ek step aage slide karta hai aur text ko dobara se padhne lagta hai — yeh waste hai. KMP bolta hai: "Jo characters main already match kar chuka hoon, unme se kuch shuruaat (prefix) wapas end (suffix) me bhi aa rahe hain — woh portion text ke saath already aligned hai, usko dobara mat compare karo." Yahi shortcut failure function π precompute karta hai.
π[i] ka matlab hai: substring S[0..i] ka sabse lamba proper prefix jo same suffix bhi ho. "Proper" zaroori hai (pura string nahi le sakte), warna fallback kabhi chhota hi nahi hoga aur infinite loop ban jaayega. Banane ka tarika: agle character ko previous border (j = π[i-1]) ke saath compare karo — match hua toh π[i]=j+1, nahi hua toh j=π[j-1] karke chhote border pe gir jao, jab tak match na mile ya j=0 na ho jaaye.
Matching me bhi yahi machine chalti hai, bas text ke upar. Mismatch pe text pointer i kabhi peeche nahi jaata — sirf pattern ka j = π[j-1] hota hai. Isi wajah se complexity O(n+m) hai: j har text character pe maximum ek baar badhta hai, aur har while-step me kam se kam ek ghatata hai, j kabhi negative nahi hota — toh total fallback bhi n se zyada nahi ho sakta. Yeh amortized argument hi KMP ki jaan hai. Yaad rakho: proper prefix = suffix, aur fall karo π[j-1] pe — exam aur interview dono me yeh bachata hai.