Rabin-Karp Algorithm for Pattern Searching
Given two strings text and pattern string, your task is to find all starting positions where the pattern appears as a substring within the text. The strings will only contain lowercase English alphabets.
While reporting the results, use 1-based indexing (i.e., the first character of the text is at position 1). You are required to identify every occurrence of the pattern, including overlapping ones, if any.
Examples:
Input: text = "birthdayboy", pattern = "birth"
Output: [1]
Explanation: The string "birth" occurs at index 1 in text.Input: text = "geeksforgeeks", pattern = "geek"
Output: [1, 9]
Explanation: The string "geek" occurs twice in text, one starts are index 1 and the other at index 9
Rabin-Karp Algorithm
In the Naive String Matching algorithm, we check whether every substring of the text of the pattern's size is equal to the pattern or not one by one.
Like the Naive Algorithm, the Rabin-Karp algorithm also check every substring. But unlike the Naive algorithm, the Rabin Karp algorithm matches the hash value of the pattern with the hash value of the current substring of text, and if the hash values match then only it starts matching individual characters. So Rabin Karp algorithm needs to calculate hash values for the following strings.
- Pattern itself
- All the substrings of the text of length m which is the size of pattern.
Hash value is used to efficiently check for potential matches between a pattern and substrings of a larger text.
How is Hash Value calculated in Rabin-Karp?
The hash value is calculated using a rolling hash function, which allows you to update the hash value for a new substring by efficiently removing the contribution of the old character and adding the contribution of the new character. This makes it possible to slide the pattern over the text and calculate the hash value for each substring without recalculating the entire hash from scratch.
For a string S of length M, the rolling hash is built like this:
hash=(((S[0]⋅b+S[1])⋅b+S[2])⋅b+⋯+S[M−1])modp
Which is equivalent to:
hash=( i=0∑M−1 S[i]⋅b M−i−1 )modp
Here's how the hash value is typically calculated in Rabin-Karp:
- Pick a prime number
p
as the modulus to reduce hash collisions. Choose a baseb
, which is often the size of the character set 256 (e.g., ASCII charset size). - Start with
hash = 0
before processing the pattern or text. - Iterate over the pattern from left to right. For each character
c
, compute the hash using the formula:\text{hash} = (\text{hash} \cdot b + c) \bmod p
- Calculate the hash for the first substring of text matching the pattern's length. Use the same method as for the pattern hash.
- Update the hash by removing the leftmost char and adding the next one.
\text{hash} = \left( \text{hash} - (\text{text}[i - \text{pattern\_length}] \cdot b^{\text{pattern\_length} - 1}) \bmod p \right) \cdot b + \text{text}[i]
- If the current text hash equals the pattern hash, verify character by character. This is needed because different substrings can have the same hash (collision).
Illustration Calculate the Hash Value of the pattern (e.g., pat)

We use the formula
Demonstration of pattern(e.g., pat) matching in the given text(e.g., txt)

To compute the hash value for a substring of length equal to the pattern, we apply the formula iteratively, updating the hash by incorporating each character’s contribution according to its position.
\text{hash} = \left( \text{hash} - (\text{text}[i - \text{pattern\_length}] \cdot b^{\text{pattern\_length} - 1}) \bmod p \right) \cdot b + \text{text}[i]
Step-by-step approach:
- Initially calculate the hash value of the pattern.
- Start iterating from the starting of the string:
- Calculate the hash value of the current substring having length m.
- If the hash value of the current substring and the pattern are same check if the substring is same as the pattern.
- If they are same, store the starting index as a valid answer. Otherwise, continue for the next substrings.
- Return the starting indices as the required answer.
// Rabin-Karp Algorithm for Pattern Searching in C++
// Reference: Introduction to Algorithms (CLRS)
#include <iostream>
#include <vector>
using namespace std;
// Function to search for all occurrences of 'pat' in 'txt' using Rabin-Karp
vector<int> search(const string &pat, const string &txt){
// Number of characters in the input alphabet (ASCII)
int d = 256;
// A prime number for modulo operations to reduce collisions
int q = 101;
// Length of the pattern
int M = pat.length();
// Length of the text
int N = txt.length();
// Hash value for pattern
int p = 0;
// Hash value for current window of text
int t = 0;
// High-order digit multiplier
int h = 1;
vector<int> ans;
// Precompute h = pow(d, M-1) % q
for (int i = 0; i < M - 1; i++)
h = (h * d) % q;
// Compute initial hash values for pattern and first window of text
for (int i = 0; i < M; i++){
p = (d * p + pat[i]) % q;
t = (d * t + txt[i]) % q;
}
// Slide the pattern over text one by one
for (int i = 0; i <= N - M; i++){
// If hash values match, check characters one by one
if (p == t){
bool match = true;
for (int j = 0; j < M; j++){
if (txt[i + j] != pat[j]){
match = false;
break;
}
}
if (match)
ans.push_back(i + 1);
}
// Calculate hash value for the next window
if (i < N - M){
t = (d * (t - txt[i] * h) + txt[i + M]) % q;
// Ensure hash value is non-negative
if (t < 0)
t += q;
}
}
return ans;
}
int main(){
string txt = "birthboy";
string pat = "birth";
// Function call to search pattern in text
vector<int> res = search(pat, txt);
for (auto it : res){
cout << it << " ";
}
cout << "\n";
return 0;
}
import java.util.ArrayList;
public class RabinKarp {
// Function to search for all occurrences of 'pat' in 'txt' using Rabin-Karp
public static ArrayList<Integer> search(String pat, String txt) {
// Number of characters in the input alphabet (ASCII)
int d = 256;
// A prime number for modulo operations to reduce collisions
int q = 101;
// Length of the pattern
int M = pat.length();
// Length of the text
int N = txt.length();
// Hash value for pattern
int p = 0;
// Hash value for current window of text
int t = 0;
// High-order digit multiplier
int h = 1;
// ArrayList to store result indices
ArrayList<Integer> ans = new ArrayList<>();
// Precompute h = pow(d, M-1) % q
for (int i = 0; i < M - 1; i++)
h = (h * d) % q;
// Compute initial hash values for pattern and first window of text
for (int i = 0; i < M; i++) {
p = (d * p + pat.charAt(i)) % q;
t = (d * t + txt.charAt(i)) % q;
}
// Slide the pattern over text one by one
for (int i = 0; i <= N - M; i++) {
// If hash values match, check characters one by one
if (p == t) {
boolean match = true;
for (int j = 0; j < M; j++) {
if (txt.charAt(i + j) != pat.charAt(j)) {
match = false;
break;
}
}
if (match)
ans.add(i + 1); // 1-based indexing
}
// Calculate hash value for the next window
if (i < N - M) {
t = (d * (t - txt.charAt(i) * h) + txt.charAt(i + M)) % q;
// Ensure hash value is non-negative
if (t < 0)
t += q;
}
}
return ans;
}
public static void main(String[] args) {
// text and pattern
String txt = "birthboy";
String pat = "birth";
// Search pattern in text
ArrayList<Integer> res = search(pat, txt);
// Print result
for (int index : res)
System.out.print(index + " ");
System.out.println();
}
}
# Rabin-Karp Algorithm for Pattern Searching in Python
# Reference: Introduction to Algorithms (CLRS)
def search(pat, txt):
# Number of characters in the input alphabet (ASCII)
d = 256
# A prime number for modulo operations to reduce collisions
q = 101
# Length of the pattern
M = len(pat)
# Length of the text
N = len(txt)
# Hash value for pattern
p = 0
# Hash value for current window of text
t = 0
# High-order digit multiplier
h = 1
ans = []
# Precompute h = pow(d, M-1) % q
for i in range(M - 1):
h = (h * d) % q
# Compute initial hash values for pattern and first window of text
for i in range(M):
p = (d * p + ord(pat[i])) % q
t = (d * t + ord(txt[i])) % q
# Slide the pattern over text one by one
for i in range(N - M + 1):
# If hash values match, check characters one by one
if p == t:
match = True
for j in range(M):
if txt[i + j] != pat[j]:
match = False
break
if match:
ans.append(i + 1)
# Calculate hash value for the next window
if i < N - M:
t = (d * (t - ord(txt[i]) * h) + ord(txt[i + M])) % q
if t < 0:
t += q
return ans
# Driver code
if __name__ == "__main__":
txt = "birthboy"
pat = "birth"
res = search(pat, txt)
print(" ".join(map(str, res)))
using System;
using System.Collections.Generic;
class GfG{
// Function to search for all occurrences of 'pat' in 'txt' using Rabin-Karp
public static List<int> search(string pat, string txt) {
// Number of characters in the input alphabet (ASCII)
int d = 256;
// A prime number for modulo operations to reduce collisions
int q = 101;
// Length of the pattern
int M = pat.Length;
// Length of the text
int N = txt.Length;
// Hash value for pattern
int p = 0;
// Hash value for current window of text
int t = 0;
// High-order digit multiplier
int h = 1;
// List to store result indices
List<int> ans = new List<int>();
// Precompute h = pow(d, M-1) % q
for (int i = 0; i < M - 1; i++)
h = (h * d) % q;
// Compute initial hash values for pattern and first window of text
for (int i = 0; i < M; i++) {
p = (d * p + pat[i]) % q;
t = (d * t + txt[i]) % q;
}
// Slide the pattern over text one by one
for (int i = 0; i <= N - M; i++) {
// If hash values match, check characters one by one
if (p == t) {
bool match = true;
for (int j = 0; j < M; j++) {
if (txt[i + j] != pat[j]) {
match = false;
break;
}
}
if (match)
ans.Add(i + 1);
}
// Calculate hash value for the next window
if (i < N - M) {
t = (d * (t - txt[i] * h) + txt[i + M]) % q;
// Ensure hash value is non-negative
if (t < 0)
t += q;
}
}
return ans;
}
static void Main() {
// Input text and pattern
string txt = "birthboy";
string pat = "birth";
// Search pattern in text
List<int> res = search(pat, txt);
// Print result
foreach (int index in res) {
Console.Write(index + " ");
}
Console.WriteLine();
}
}
// Rabin-Karp Algorithm for Pattern Searching in JavaScript
// Reference: Introduction to Algorithms (CLRS)
function search(pat, txt) {
// Number of characters in the input alphabet (ASCII)
const d = 256;
// A prime number for modulo operations to reduce collisions
const q = 101;
// Length of the pattern
const M = pat.length;
// Length of the text
const N = txt.length;
// Hash value for pattern
let p = 0;
// Hash value for current window of text
let t = 0;
// High-order digit multiplier
let h = 1;
const ans = [];
// Precompute h = pow(d, M-1) % q
for (let i = 0; i < M - 1; i++) {
h = (h * d) % q;
}
// Compute initial hash values for pattern and first window of text
for (let i = 0; i < M; i++) {
p = (d * p + pat.charCodeAt(i)) % q;
t = (d * t + txt.charCodeAt(i)) % q;
}
// Slide the pattern over text one by one
for (let i = 0; i <= N - M; i++) {
// If hash values match, check characters one by one
if (p === t) {
let match = true;
for (let j = 0; j < M; j++) {
if (txt[i + j] !== pat[j]) {
match = false;
break;
}
}
if (match) ans.push(i + 1);
}
// Calculate hash value for the next window
if (i < N - M) {
t = (d * (t - txt.charCodeAt(i) * h) +
txt.charCodeAt(i + M)) % q;
if (t < 0) t += q;
}
}
return ans;
}
// Driver code
const txt = "birthboy";
const pat = "birth";
const res = search(pat, txt);
console.log(res.join(" "));
Output
1
Time Complexity: O(n + m), but in the worst case, when all characters of the pattern and text are identical causing all substring hash values of the text to match the pattern’s hash, the time complexity degrades to O(nm).
Auxiliary Space: O(1)
Limitations of Rabin-Karp Algorithm
When the hash value of the pattern matches with the hash value of a window of the text but the window is not the actual pattern then it is called a spurious hit. Spurious hit increases the time complexity of the algorithm. In order to minimize spurious hit, we use good hash function. It greatly reduces the spurious hit.
Related Posts:
Searching for Patterns | Set 1 (Naive Pattern Searching)
Searching for Patterns | Set 2 (KMP Algorithm)