Info & Theory
Rabin–Karp finds occurrences of a pattern of length
m inside a text of length n by
sliding a window of size m across the text and
comparing a numeric fingerprint — a hash — of the
window against the hash of the pattern, instead of comparing
characters directly at every position.
The polynomial rolling hash
Each window of characters c₀ c₁ … c(m−1) is
treated as digits of a number in base b:
h = (c₀·b^(m−1) + c₁·b^(m−2) + … + c(m−1)) mod pbis a base (e.g. 256),pa large prime (e.g. 1,000,000,007) that keeps the hash bounded and reduces collisions.
Sliding in O(1)
Recomputing the hash from scratch at every position would cost
O(m) per shift. Instead, Rabin–Karp updates it
incrementally: remove the contribution of the outgoing
character, shift the remaining digits up one place, and add
the incoming character —
h′ = ((h − text[i]·b^(m−1))·b + text[i+m]) mod p,
adding p before the final mod whenever the
subtraction goes negative. This costs O(1) per
shift regardless of m.
Why verify after a hash match
Different windows can occasionally collide to the same hash value even though their characters differ — a spurious hit. Whenever the window hash equals the pattern hash, Rabin–Karp performs an explicit character-by-character comparison to confirm a true match before reporting it, guaranteeing correctness regardless of collisions.
Complexity
Average and typical-case running time is O(n + m),
since verification is only triggered on (rare) hash matches.
Worst case is O(n·m) if many spurious hits force
repeated full verifications — extremely unlikely with a large
prime modulus, but demonstrable here with the small-modulus
option. Rabin–Karp's hashing idea also extends naturally to
searching for multiple patterns at once in a single
pass, which single-pattern algorithms cannot do as cheaply.