What does it solve?
Find occurrences of a pattern P in text T by comparing hashes instead of characters. Compute the pattern's hash once, then slide a window over the text keeping a running hash.
Key insight: a rolling hash updates in O(1): drop the leaving character's contribution, shift, add the entering one. When a window hash equals the pattern hash it's a candidate, verify character-by-character to rule out a spurious hit (a hash collision). Average cost is O(N + M); worst case O(N·M) if everything collides.
The core idea
h(w) = (w0·b^(m-1) + … + w_{m-1}) mod q
// roll the window one step right:
roll = ( (h − T[i]·b^(m-1))·b
+ T[i+m] ) mod q
Complexity
Average case with a good hash. Each roll is O(1); verification is rare. Worst case O(N·M) when hashes collide on every window.
Just the two hashes, the high-order multiplier b^(m-1), and a few counters. No table proportional to input size.
Examples & edge cases
Step-by-step table
| Step | Phase | start | window | winHash | patHash | Hash eq? | Verify | Matches |
|---|
C++ implementation
#include <bits/stdc++.h> using namespace std; // Rabin-Karp: return all start indices of p in t vector<int> rabinKarp(const string& t, const string& p) { const long long b = 26, q = 101; // base and a prime modulus int n = t.size(), m = p.size(); vector<int> res; if (m > n || m == 0) return res; long long h = 1; // b^(m-1) % q, the high-order weight for (int i = 0; i < m - 1; i++) h = (h * b) % q; long long ph = 0, wh = 0; // pattern hash, window hash for (int i = 0; i < m; i++) { ph = (b * ph + p[i]) % q; wh = (b * wh + t[i]) % q; } for (int s = 0; s <= n - m; s++) { if (ph == wh) { // hashes agree → candidate if (t.compare(s, m, p) == 0) // verify char-by-char res.push_back(s); } if (s < n - m) { // roll to the next window wh = (b * (wh - t[s] * h) + t[s + m]) % q; if (wh < 0) wh += q; // keep it non-negative } } return res; } int main() { auto hits = rabinKarp("ABCCDABCAB", "ABC"); for (int x : hits) cout << x << " "; // 0 5 return 0; }
My Notes