Yasir Explains/Algorithms/String Algorithms/Rabin–Karp Algorithm
String Algorithms

Rabin–Karp Algorithm

On this page

Rolling Hash IdeaAlgorithm OutlineWhen Rabin–Karp HelpsPseudocodeComplexity
String Algorithms

Rabin–Karp Algorithm

Use rolling polynomial hashes to filter candidate alignments before verifying with exact comparison.

Rolling Hash Idea

Treat substrings of length m as numbers in base d (alphabet size, e.g. 256 for bytes). A hash function maps each length-m window T[s..s+m−1] to an integer. Instead of recomparing all m characters for every shift, update the hash in O(1) when the window slides by one: subtract the contribution of the outgoing character, add the incoming one, modulo a prime q (to keep numbers bounded).

If the hash of the window equals the hash of P, verify with an explicit character-by-character check — hashes can collide (two different strings, same hash).

Algorithm Outline

  1. Choose base d and modulus q (often a large prime).
  2. Compute h(P) and the hash of the first window T[0..m−1].
  3. For each shift s, if window hash equals h(P), compare T[s..s+m−1] to P; on match, record s.
  4. Roll the hash from s to s+1 using the recurrence for polynomial rolling hash.

Monte Carlo variant: skip verification and accept hash equality (rare false positives). Las Vegas variant: always verify — our description assumes this for correctness.

When Rabin–Karp Helps

Expected time can be O(n + m) when collisions are rare and verifications are few — useful for multiple patterns (compute multiple hashes) or 2D pattern search with 2D rolling hashes.

Worst case remains O(nm) if a malicious text forces many hash matches and full verifications (e.g. all windows hash-collide with P). Good hash parameters and randomization reduce collision probability in practice.

Pseudocode

Below, h is the rolling hash of the current window; t_s denotes the numeric value of window starting at s (mod q). The roll step uses Horner-style updates.

1RABIN-KARP(T, n, P, m, d, q)
2 h = d^(m-1) mod q // precompute for rolling
3 p = 0 // hash of pattern
4 t = 0 // hash of first window
5 for i = 1 to m
6 p = (d*p + P[i]) mod q
7 t = (d*t + T[i]) mod q
8 occurrences = []
9 for s = 0 to n - m
10 if p = t
11 if P[1..m] = T[s+1 .. s+m] // verify
12 occurrences.append(s)
13 if s < n - m
14 t = (d*(t - T[s+1]*h) + T[s+m+1]) mod q
15 if t < 0
16 t = t + q // keep non-negative if using mod arithmetic
17 return occurrences

Complexity

Preprocessing / first window: O(m) to compute initial hash and pattern hash.

Rolling: O(n − m) updates, O(1) each.

Verifications: O(m) per spurious hash match. Total: O(n + m) average case with few collisions; O(nm) worst case if every window must be verified.

Complexity Analysis

Time Complexity

O(n + m) average; O(nm) worst case

Space Complexity

O(1) beyond input

Worst case if many hash collisions require full verifications

Growth Rate Comparison

n (input size)O(1)O(log n)O(n)O(n log n)O(n²)