Pattern matching, hashed. Instead of comparing characters, Rabin-Karp computes a hash of the pattern and a hash of every equal-length window of the text — then compares numbers instead of letters. A good hash rejects almost every window instantly, and a trick called the rolling hash recomputes each window in O(1).
How It Works
- Hash the pattern:
hash(s) = (c₁·bᵐ + c₂·bᵐ⁻¹ + ... + cₘ) mod p, using a baseband primep. - Roll the window: slide one character at a time; each new hash derives from the previous in
O(1):h(win+1) = ((h(win) − T[win]·b^(m−1)) · b + T[win+m]) mod p - Compare hashes: equal hashes mean a probable match — verify the actual characters to rule out collisions.
- Record confirmed matches.
Key Insight
The rolling hash makes every slide cheap: subtract the outgoing leftmost character’s contribution, shift everything left by one, and add the new character. So the whole scan is O(n) if collisions are rare — and a well-chosen prime keeps them rare. That’s why the average case is O(n + m) but the worst case O(n·m) (e.g., when a pathological pattern hashes equal to nearly every window).
Worked Example
The visualizer searches for pattern P = 31415 in the digit text T = 2359023141526739921.
The pattern’s hash is computed once. The window slides left to right; most windows hash to something different and are rejected with a single integer comparison — no character work. The window starting at text position 6 hashes equal to the pattern, so the algorithm verifies character-by-character: 3 1 4 1 5 all agree, and the match at position 6 is reported. Total work stays near-linear because only that one window survived the hash filter.
Edge Cases & Pitfalls
- Collisions are real: equal hashes can occur without a match — always verify characters before reporting.
- Modulo arithmetic negatives:
(a − b) mod pcan go negative; addpbefore reducing. - Base choice: using a base larger than the alphabet (e.g. 256 for ASCII) reduces collisions.
- Prime choice: a large prime reduces collisions; a small one makes them likely.
- Worst case: adversarial inputs can force a verify on every window →
O(n·m).
Comparison: Rabin-Karp vs KMP vs Naive
| Aspect | Naive | KMP | Rabin-Karp |
|---|---|---|---|
| Average | O(n·m) | O(n + m) | O(n + m) |
| Worst | O(n·m) | O(n + m) | O(n·m) |
| Space | O(1) | O(m) | O(1) |
| Multi-pattern | No | No | Yes |
Applications
- Plagiarism detection — compare many document windows against many patterns
- Multi-pattern search — check one window hash against a set of pattern hashes
- Duplicate detection — rolling hashes power dedup and similarity tools
Practice Trajectory
- Compute the pattern hash for
31415with a small base by hand. - Roll the hash from the first window to the second and verify the
O(1)update. - Watch the visualizer reject the non-matching windows on hash alone.
- Construct a case where two strings collide under a small modulus.
- Extend to two patterns and verify both are found in one text pass.