Open In App

Rabin-Karp Algorithm for Pattern Searching

Last Updated : 03 Jun, 2025
Suggest changes
Share
Like Article
Like
Report

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 base b, 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)

calculation_of_the_hash_value_of_the_pat_

We use the formula \text{hash} = (\text{hash} \cdot b + c) \bmod p to compute the hash value of the pattern string.

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

calculation_of_the_hash_value_of_pat_

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.
C++
// 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; } 
Java
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();  } } 
Python
# 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))) 
C#
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();  } } 
JavaScript
// 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)



Next Article

Similar Reads