Exercises — Rabin-Karp — rolling hash, O(n+m) expected
Before we start, we fix one shared convention so no symbol is ever unexplained:
The figure below is the one picture the whole page leans on — keep it in view.

Level 1 — Recognition
L1.1 — Spot the digit weights
For the string "cat" (so ) with base , write the polynomial for its hash before any mod. Which character carries the weight ?
Recall Solution
WHAT: we expand term by term. WHY: the leftmost character is the most significant digit, so it multiplies the highest power of .
Compute: , plus , plus .
The first character c carries .
L1.2 — What does a hash mismatch prove?
You compute and a window's hash . What can you conclude, and what must you do?
Recall Solution
Conclude: the strings are definitely different. Equal strings always produce equal hashes, so unequal hashes force unequal strings. Do: skip this window instantly — no character check needed. (Contrast: a hash match only means "probably equal," so it needs verification.)
Level 2 — Application
L2.1 — Compute a hash mod
Compute with .
Recall Solution
From L1.1 the raw value is . WHY mod: we keep it small and bounded. , since and .
L2.2 — One roll by hand
Text (), , , . You already have . Compute , the hash of window "ats", using Drop, Slide, Add.
Recall Solution
Precompute . Since , .
Drop leading c: .
Keep non-negative: .
Slide () and Add trailing s: .
, so .
Check by direct formula: ; . ✓ The roll and the direct computation agree — that is the whole point.
L2.3 — Find the match position
Search in , , , . Report every index of a match.
Recall Solution
.
Window 0 "aa" → skip.
Roll to window 1 "ab": . . Matches → verify → "ab"=="ab" ✓.
Match at index 1.
Level 3 — Analysis
L3.1 — Why a tiny prime is dangerous
With and , hash the two-letter strings "ac" () and "ba" (). Do they collide? Explain the consequence for running time.
Recall Solution
. . They collide () even though the strings differ. Consequence: with a small , many windows produce equal hashes, so we run the verification constantly → the "expected " collapses toward the worst case . This is exactly why we choose a large prime like . See Modular Arithmetic and Birthday Paradox.
L3.2 — Collision probability reasoning
With a good random hash mod prime , the chance a single wrong window collides is about . If a text has windows and , roughly how many spurious verifications do we expect?
Recall Solution
WHY this tool: expected count (number of trials) (per-trial probability), the linearity-of-expectation shortcut. About one in a thousand whole searches does even a single wasted verification — negligible. That is why total expected cost stays .
L3.3 — Construct a worst case
Give a text/pattern family (with a chosen ) that forces . Explain why.
Recall Solution
Take ( copies) and ( copies). Every window equals , so every hash matches and every window triggers a full verification. Total . Note this is a genuine-match worst case; an adversarial collision worst case instead uses a known small and crafts distinct windows that all hash to . Both defeat the average-case bound. This is why Knuth-Morris-Pratt (guaranteed ) is preferred when adversaries are possible.
Level 4 — Synthesis
L4.1 — Two-hash defence
You use two independent hashes and with , . A wrong window collides on both only if it collides on each. Estimate the combined per-window false-positive rate and compare to a single hash mod .
Recall Solution
WHY independence multiplies: two independent events both happen with probability equal to the product. Combined rate . A single hash mod gives . So two small primes () already beat one modulus of : . Lesson: two independent moduli multiply their protection, which is why double hashing is so strong. See String Hashing for Substring Comparison.
L4.2 — Full trace over a real text
Search in , , , . Trace all windows and list match indices.
Recall Solution
. . Codes of : .
- Window 0
"ba": . → skip. - Roll → Window 1
"ab": dropb: ; slide+addb: . → verify"ab"✓. Match at 1. - Roll → Window 2
"ba": dropa: ; slide+adda: . → skip. - Roll → Window 3
"ab": dropb: ; slide+addb: . → verify ✓. Match at 3. Matches: indices 1 and 3. (Direct check:babab[1..2]=ab, [3..4]=ab. ✓)
Level 5 — Mastery
L5.1 — Design a robust searcher
You must search a pattern in a text supplied by an untrusted user (possible adversary), needing near-guaranteed correctness and good speed. State your full design and justify each choice against the failure modes you learned.
Recall Solution
Design:
- Use double hashing: two random large primes , random bases . Why: combined collision rate — even a crafted adversary cannot predict the random bases, so L3.3's collision attack fails.
- Precompute once for each hash. Why: recomputing inside the loop makes each roll and kills the speedup (the L2 precompute mistake at scale).
- Guard subtraction with
((x)%q+q)%q. Why: prevents negative-hash corruption (L2 trap). - Still verify char-by-char on a (double) hash hit. Why: keeps correctness exact, and with double hashing verifications are essentially only on true matches, so expected time stays .
- Fallback: if guaranteed worst-case is mandated (e.g. hard real-time), switch to Knuth-Morris-Pratt or Z-Algorithm, which need no randomness.
L5.2 — Prove the roll algebraically
Show that the Drop-Slide-Add formula produces exactly , ignoring mod. Where do we actually need mod to make it valid?
Recall Solution
Write . The leading term is . Drop: . Slide (): . Re-index with : — this is the hash of but missing its last character and with each weight one power too high... precisely, it equals the first terms of . Add : fills the final low-order digit, giving . ∎ Mod validity: addition, subtraction, and multiplication all commute with "" — that is a theorem of Modular Arithmetic. So doing every step mod gives the same remainder as computing the giant number first and reducing at the end. Division would not survive mod, which is why our hash uses only .
Recall One-line self-test
Rolling update formula ::: Why keep verification after a double-hash hit? ::: To stay exactly correct; the rare/adversarial collision is the only thing between "probably equal" and "equal."
Connections
- Rabin-Karp — rolling hash, O(n+m) expected — the parent theory these drills exercise
- Hashing — polynomial/modular hash foundations used throughout
- Modular Arithmetic — why survive mod but division is fragile (L5.2, L2 traps)
- Birthday Paradox — collision-probability intuition behind L3.2
- Knuth-Morris-Pratt, Z-Algorithm — worst-case-guaranteed fallbacks (L3.3, L5.1)
- String Hashing for Substring Comparison — the double-hashing idea from L4.1