KMP algorithm — failure function, O(n+m) — full derivation
3.8.2· Coding › String Algorithms
KAUNSI problem solve kar rahe hain?
KYA: Pattern (length ) ke saare occurrences text (length ) mein dhundho.
KYUN naive slow hai: Naive matching har shift par ko compare karti hai. Adversarial input jaise , par yeh kaam karta hai, baar baar same text characters ko re-scan karte hue.
KAISE KMP jeetta hai: Text pointer sirf aage hi move karta hai. Jab pattern position par mismatch hoti hai, reset karne ki jagah, hum set karte hain — pattern ko uske longest reusable prefix par jump karte hue. Har text char amortized baar "examine" hota hai → .
Failure function (poora trick)
Worked example: ababaca ke liye banao
| 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 |
Kyun π[4]=3? ababa: prefix aba = suffix aba. Usse lamba (abab) suffix nahi hai. Toh 3.
Kyun π[5]=0? ababac c par khatam hota hai; ababac ka koi prefix c par khatam nahi hota, sivaaye poore string ke (jo proper nahi hai). Toh 0.
-computation algorithm ko scratch se DERIVE karna
Hum incrementally build karte hain. Maano humein pata hai aur chahiye. = previous position ke liye best prefix-suffix ki length.
Case 1 — extend kar sakte hain. Agar , toh prefix S[0..j-1] jo suffix tha, dono ends par ek char se badh sakta hai. Toh .
Yeh step kyun? Length ka ek border (prefix=suffix) S[0..i-1] ke liye, plus ek matching char, S[0..i] ke liye length ka border deta hai.
Case 2 — mismatch, fall back karo. Agar aur , toh next-best candidate border length hai. Hum set karte hain aur retry karte hain.
Kyun ? se chhota sabse lamba border jo current prefix ka bhi border ho, woh usi border ka sabse lamba border hai — jo hai . Yeh recursion nested borders ki chain mein neeche jaati hai.
Case 3 — bottom aa gaya. Agar aur phir bhi 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
Matching loop DERIVE karna
Wohi machine text par chalao. index kare ko, index kare ko.
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 matchesKyun mismatch par hum i ko back nahi lete? Kyunki prefix P[0..π[j-1]-1]
guaranteed equal hai pehle se scan kiye gaye text ke. Dobara padhna ek jaani-maani equality ko re-confirm karna hoga. Isliye sirf aage badh'ta hai.
WHY yeh O(n+m) hai — amortized proof
Yahi key insight hai jo KMP ko naive se alag karti hai: fallback ki amortized cost is baat se bounded hai ki kabhi kitna badha.
Full match example: abab, ababaababab
Pehle abab ke liye : [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 |
Kyun report 0 phir 6 phir 7? Overlapping occurrences abab indices 0, 6, 7 par.
i=5 par j=3 se 1 par fallback ne matched a ko reuse kiya, restart karne ki jagah.
Recall Feynman: ek 12-saal ke bacche ko samjhao
Socho tum ek word ko letter by letter match kar rahe ho aur 5th letter par galti ho gayi. Ek bewakoof robot poori tarah peeche jaata aur poora word phir se shuru karta. Ek smart robot yaad rakhta hai: "jo last kuch letters maine abhi likhe hain woh mere word ke shuru jaisi hain!" Toh woh restart nahi karta — woh pretend karta hai ki usne pehle se shuru likh liya aur continue karta hai. "Failure function" sirf ek cheat-sheet hai jo robot ko batati hai, har jagah ke liye, ki galti hone par kitne letters woh rakh sakta hai. Kyunki yeh kabhi book ko dobara nahi padhta, yeh bahut fast hai.
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 Z-array ke zariye
- Rabin-Karp — hashing-based matching, expected
- Aho-Corasick — KMP failure links ko kaafi patterns tak generalize karta hai (a trie of fail links)
- Suffix Automaton & Suffix Array — repeated queries ke liye heavier structures
- Amortized Analysis — bound ke liye use hone wala potential argument
- Borders and Periods of Strings — ka smallest period deta hai