RabinKarp algorithm for Pattern Searching in Matrix (original) (raw)
Last Updated : 08 Feb, 2025
Given the 2-d matrices **txt[][] of order **n1 * m1 and **pat[][] of order **n2 * m2. The task is to find the indices of matrix txt[][] where the matrix **pat[][] is present.
**Examples:
**Input: txt[][] = [ [ G, H, I, P ],
[ J, K, L, Q ],
[ R, G, H, I ],
[ S, J, K, L ] ]
pat[][] = [ [G, H, I ],
[ J, K, L ] ]
**Output: [[0, 0] [2, 1]]
**Explanation: Pattern pat[][] can be found at index (0, 0) and (2, 1) of text txt[][].
**Approach:
The idea is to use Rabin - Karp Algorithm, to search the indices of text **txt[][] where the patter **pat[][] is present. To do so, firstly find the hash of each columns of **txt[][] and **pat[][] and **compare the hash values. For any column if hash values are **equals than **check for the corresponding **rows values.
Thereafter, apply Rabin - Karp algorithm for column hashes, and if a match is found, compare txt[][] and pat[][] matrices for the specific rows and columns. Otherwise, slide down the column hashes by 1 row in the matrix txt[][] using a rolling hash.
In order to find the hash value of a substring of size n in a text using rolling hash remove the **first character from the string and **add the **next character to the string.
Repeat it for all the hash values and if we found any **pat[][] match in **txt[][] then store the indices of top most cell of the **txt[][].
C++ `
// C++ program to implement Rabin-Karp Algorithm // for pattern searching in a 2-D matrix.
#include <bits/stdc++.h> using namespace std;
// Function to find a ^ n % mod int findPower(int a, int n, int mod) { if(n == 0) { return 1; } if(n == 1) { return a % mod; } int pow = findPower(a, n / 2, mod); if(n & 1) { return ((a % mod) * (pow % mod) * (pow % mod)) % mod; } else { return ((pow % mod) * (pow % mod)) % mod; } }
// Function to find the first hash of first n rows // where n is the number of rows in the pattern vector findHash(vector<vector> &mat, int row, int mod, int radix) { vector hash; int col = mat[0].size(); for(int i = 0; i < col; i++) { int h = 0; for(int j = 0; j < row; j++) { h = (((h * radix) % mod) + (mat[j][i] % mod)) % mod; } hash.push_back(h); } return hash; }
// Function to check if all values of // pattern matches with the text bool check(vector<vector> &txt, vector<vector> &pat, int r, int c) {
for(int i = 0; i < pat.size(); i++) {
for(int j = 0; j < pat[0].size(); j++) {
if(pat[i][j] != txt[i + r][j + c]) {
return false;
}
}
}
return true;
}
// Function to calculate rolling hash for columns void colRollingHash(vector<vector> &txt, vector &txtHash, int row, int n2, int rowPow, int mod, int radix) {
for(int i = 0; i < txtHash.size(); i++) {
txtHash[i] = (txtHash[i] % mod - ((txt[row][i] % mod)
* (rowPow % mod)) % mod) % mod;
txtHash[i] = ((txtHash[i] % mod) * (radix % mod)) % mod;
txtHash[i] = ((txtHash[i] % mod) +
(txt[row + n2][i] % mod)) % mod;
}
}
// Function to find the indices of txt[][] // where pat[][] is present vector<vector> searchPattern(vector<vector> &txt, vector<vector> &pat) { int n1 = txt.size(), m1 = txt[0].size(); int n2 = pat.size(), m2 = pat[0].size();
int mod = 257, radix = 256;
// stores all the resultant indices
vector<vector<int>> res;
// highest power for row hashing
int rowPow = findPower(radix, n2 - 1, mod);
// highest power for col hashing
int colPow = findPower(radix, m2 - 1, mod);
// stores column hash of n2 rows of txt[][]
vector<int> txtHash = findHash(txt, n2, mod, radix);
// stores column hash of n2 rows of pat[][]
vector<int> patHash = findHash(pat, n2, mod, radix);
// stores has of entire matrix pat[][]
int patHashVal = 0;
for(int i = 0; i < m2; i++) {
patHashVal = (patHashVal * radix + patHash[i]) % mod;
}
for(int i = 0; i <= n1 - n2; i++) {
// stores hash of rows of txt[][]
int txtHashVal = 0;
for(int j = 0; j < m2; j++) {
txtHashVal = (txtHashVal * radix + txtHash[j]) % mod;
}
for(int j = 0; j <= m1 - m2; j++) {
if(txtHashVal == patHashVal) {
if(check(txt, pat, i, j)) {
res.push_back({i, j});
}
}
// calculate hash for next set of columns
txtHashVal = (txtHashVal % mod - ((txtHash[j] % mod) *
(colPow % mod)) % mod + mod) % mod;
txtHashVal = ((txtHashVal % mod) * (radix % mod)) % mod;
if(j + m2 < m1) {
txtHashVal = ((txtHashVal % mod) +
(txtHash[j + m2] % mod)) % mod;
}
}
if(i < n1 - n2) {
// calculate hash for next set of rows
colRollingHash(txt, txtHash, i, n2, rowPow, mod, radix);
}
}
return res;
}
int main() { vector<vector> txt = { {'G', 'H', 'I', 'P'}, {'J', 'K', 'L', 'Q'}, {'R', 'G', 'H', 'I'}, {'S', 'J', 'K', 'L'} }; vector<vector> pat = { {'G', 'H', 'I'}, {'J', 'K', 'L'} }; vector<vector> res = searchPattern(txt, pat); for(int i = 0; i<res.size(); i++) { cout << "[" << res[i][0] << ", " << res[i][1] << "]" << " "; } return 0; }
Java
// Java program to implement Rabin-Karp Algorithm // for pattern searching in a 2-D matrix.
import java.util.*;
class GFG {
// Function to find a ^ n % mod
static int findPower(int a, int n, int mod) {
if (n == 0) {
return 1;
}
if (n == 1) {
return a % mod;
}
int pow = findPower(a, n / 2, mod);
if ((n & 1) == 1) {
return ((a % mod) * (pow % mod) * (pow % mod)) % mod;
} else {
return ((pow % mod) * (pow % mod)) % mod;
}
}
// Function to find the first hash of first n rows
// where n is the number of rows in the pattern
static List<Integer> findHash(char[][] mat, int row, int mod, int radix) {
List<Integer> hash = new ArrayList<>();
int col = mat[0].length;
for (int i = 0; i < col; i++) {
int h = 0;
for (int j = 0; j < row; j++) {
h = (((h * radix) % mod) + (mat[j][i] % mod)) % mod;
}
hash.add(h);
}
return hash;
}
// Function to check if all values of
// pattern matches with the text
static boolean check(char[][] txt, char[][] pat, int r, int c) {
for (int i = 0; i < pat.length; i++) {
for (int j = 0; j < pat[0].length; j++) {
if (pat[i][j] != txt[i + r][j + c]) {
return false;
}
}
}
return true;
}
// Function to calculate rolling hash for columns
static void colRollingHash(char[][] txt, List<Integer> txtHash, int row, int n2, int rowPow, int mod, int radix) {
for (int i = 0; i < txtHash.size(); i++) {
txtHash.set(i, (txtHash.get(i) % mod - ((txt[row][i] % mod) * (rowPow % mod)) % mod + mod) % mod);
txtHash.set(i, ((txtHash.get(i) % mod) * (radix % mod)) % mod);
txtHash.set(i, ((txtHash.get(i) % mod) + (txt[row + n2][i] % mod)) % mod);
}
}
// Function to find the indices of txt[][]
// where pat[][] is present
static List<int[]> searchPattern(char[][] txt, char[][] pat) {
int n1 = txt.length, m1 = txt[0].length;
int n2 = pat.length, m2 = pat[0].length;
int mod = 257, radix = 256;
// stores all the resultant indices
List<int[]> res = new ArrayList<>();
// highest power for row hashing
int rowPow = findPower(radix, n2 - 1, mod);
// highest power for col hashing
int colPow = findPower(radix, m2 - 1, mod);
// stores column hash of n2 rows of txt[][]
List<Integer> txtHash = findHash(txt, n2, mod, radix);
// stores column hash of n2 rows of pat[][]
List<Integer> patHash = findHash(pat, n2, mod, radix);
// stores hash of entire matrix pat[][]
int patHashVal = 0;
for (int i = 0; i < m2; i++) {
patHashVal = (patHashVal * radix + patHash.get(i)) % mod;
}
for (int i = 0; i <= n1 - n2; i++) {
// stores hash of rows of txt[][]
int txtHashVal = 0;
for (int j = 0; j < m2; j++) {
txtHashVal = (txtHashVal * radix + txtHash.get(j)) % mod;
}
for (int j = 0; j <= m1 - m2; j++) {
if (txtHashVal == patHashVal) {
if (check(txt, pat, i, j)) {
res.add(new int[]{i, j});
}
}
// calculate hash for next set of columns
txtHashVal = (txtHashVal % mod - ((txtHash.get(j) % mod) * (colPow % mod)) % mod + mod) % mod;
txtHashVal = ((txtHashVal % mod) * (radix % mod)) % mod;
if (j + m2 < m1) {
txtHashVal = ((txtHashVal % mod) + (txtHash.get(j + m2) % mod)) % mod;
}
}
if (i < n1 - n2) {
// calculate hash for next set of rows
colRollingHash(txt, txtHash, i, n2, rowPow, mod, radix);
}
}
return res;
}
public static void main(String[] args) {
char[][] txt = {
{'G', 'H', 'I', 'P'},
{'J', 'K', 'L', 'Q'},
{'R', 'G', 'H', 'I'},
{'S', 'J', 'K', 'L'}
};
char[][] pat = {
{'G', 'H', 'I'},
{'J', 'K', 'L'}
};
List<int[]> res = searchPattern(txt, pat);
for (int[] r : res) {
System.out.print("[" + r[0] + ", " + r[1] + "] ");
}
}
}
Python
Python program to implement Rabin-Karp Algorithm
for pattern searching in a 2-D matrix.
def find_power(a, n, mod): if n == 0: return 1 if n == 1: return a % mod pow_val = find_power(a, n // 2, mod) if n & 1: return (a % mod * pow_val % mod * pow_val % mod) % mod else: return (pow_val % mod * pow_val % mod) % mod
def find_hash(mat, row, mod, radix): hash_list = [] col = len(mat[0]) for i in range(col): h = 0 for j in range(row): h = ((h * radix) % mod + ord(mat[j][i]) % mod) % mod hash_list.append(h) return hash_list
def check(txt, pat, r, c): for i in range(len(pat)): for j in range(len(pat[0])): if pat[i][j] != txt[i + r][j + c]: return False return True
def col_rolling_hash(txt, txt_hash, row, n2, row_pow, mod, radix): for i in range(len(txt_hash)): txt_hash[i] = (txt_hash[i] % mod - (ord(txt[row][i]) % mod * row_pow % mod) % mod + mod) % mod txt_hash[i] = (txt_hash[i] * radix) % mod txt_hash[i] = (txt_hash[i] + ord(txt[row + n2][i]) % mod) % mod
def search_pattern(txt, pat): n1, m1 = len(txt), len(txt[0]) n2, m2 = len(pat), len(pat[0])
mod, radix = 257, 256
# stores all the resultant indices
res = []
# highest power for row hashing
row_pow = find_power(radix, n2 - 1, mod)
# highest power for col hashing
col_pow = find_power(radix, m2 - 1, mod)
# stores column hash of n2 rows of txt[][]
txt_hash = find_hash(txt, n2, mod, radix)
# stores column hash of n2 rows of pat[][]
pat_hash = find_hash(pat, n2, mod, radix)
# stores hash of entire matrix pat[][]
pat_hash_val = 0
for i in range(m2):
pat_hash_val = (pat_hash_val * radix + pat_hash[i]) % mod
for i in range(n1 - n2 + 1):
# stores hash of rows of txt[][]
txt_hash_val = 0
for j in range(m2):
txt_hash_val = (txt_hash_val * radix + txt_hash[j]) % mod
for j in range(m1 - m2 + 1):
if txt_hash_val == pat_hash_val:
if check(txt, pat, i, j):
res.append([i, j])
# calculate hash for next set of columns
txt_hash_val = (txt_hash_val % mod - (txt_hash[j] % mod * col_pow % mod) % mod + mod) % mod
txt_hash_val = (txt_hash_val * radix) % mod
if j + m2 < m1:
txt_hash_val = (txt_hash_val + txt_hash[j + m2]) % mod
if i < n1 - n2:
# calculate hash for next set of rows
col_rolling_hash(txt, txt_hash, i, n2, row_pow, mod, radix)
return res
Driver code
txt = [ ['G', 'H', 'I', 'P'], ['J', 'K', 'L', 'Q'], ['R', 'G', 'H', 'I'], ['S', 'J', 'K', 'L'] ] pat = [ ['G', 'H', 'I'], ['J', 'K', 'L'] ]
res = search_pattern(txt, pat) for r in res: print(f"[{r[0]}, {r[1]}]", end=" ")
C#
// C# program to implement Rabin-Karp Algorithm // for pattern searching in a 2-D matrix.
using System; using System.Collections.Generic;
class GFG { // Function to find a ^ n % mod static int FindPower(int a, int n, int mod) { if (n == 0) return 1; if (n == 1) return a % mod; int pow = FindPower(a, n / 2, mod); if ((n & 1) == 1) { return ((a % mod) * (pow % mod) * (pow % mod)) % mod; } else { return ((pow % mod) * (pow % mod)) % mod; } }
// Function to find the first hash of first n rows
// where n is the number of rows in the pattern
static List<int> FindHash(char[][] mat, int row, int mod, int radix) {
List<int> hash = new List<int>();
int col = mat[0].Length;
for (int i = 0; i < col; i++) {
int h = 0;
for (int j = 0; j < row; j++) {
h = (((h * radix) % mod) + (mat[j][i] % mod)) % mod;
}
hash.Add(h);
}
return hash;
}
// Function to check if all values of
// pattern matches with the text
static bool Check(char[][] txt, char[][] pat, int r, int c) {
for (int i = 0; i < pat.Length; i++) {
for (int j = 0; j < pat[0].Length; j++) {
if (pat[i][j] != txt[i + r][j + c]) {
return false;
}
}
}
return true;
}
// Function to calculate rolling hash for columns
static void ColRollingHash(char[][] txt, List<int> txtHash, int row, int n2, int rowPow, int mod, int radix) {
for (int i = 0; i < txtHash.Count; i++) {
txtHash[i] = (txtHash[i] % mod - ((txt[row][i] % mod) * (rowPow % mod)) % mod + mod) % mod;
txtHash[i] = ((txtHash[i] % mod) * (radix % mod)) % mod;
txtHash[i] = ((txtHash[i] % mod) + (txt[row + n2][i] % mod)) % mod;
}
}
// Function to find the indices of txt[][]
// where pat[][] is present
static List<int[]> SearchPattern(char[][] txt, char[][] pat) {
int n1 = txt.Length, m1 = txt[0].Length;
int n2 = pat.Length, m2 = pat[0].Length;
int mod = 257, radix = 256;
// Stores all the resultant indices
List<int[]> res = new List<int[]>();
// Highest power for row hashing
int rowPow = FindPower(radix, n2 - 1, mod);
// Highest power for col hashing
int colPow = FindPower(radix, m2 - 1, mod);
// Stores column hash of n2 rows of txt[][]
List<int> txtHash = FindHash(txt, n2, mod, radix);
// Stores column hash of n2 rows of pat[][]
List<int> patHash = FindHash(pat, n2, mod, radix);
// Stores hash of entire matrix pat[][]
int patHashVal = 0;
for (int i = 0; i < m2; i++) {
patHashVal = (patHashVal * radix + patHash[i]) % mod;
}
for (int i = 0; i <= n1 - n2; i++) {
// Stores hash of rows of txt[][]
int txtHashVal = 0;
for (int j = 0; j < m2; j++) {
txtHashVal = (txtHashVal * radix + txtHash[j]) % mod;
}
for (int j = 0; j <= m1 - m2; j++) {
if (txtHashVal == patHashVal) {
if (Check(txt, pat, i, j)) {
res.Add(new int[] { i, j });
}
}
// Calculate hash for next set of columns
txtHashVal = (txtHashVal % mod - ((txtHash[j] % mod) * (colPow % mod)) % mod + mod) % mod;
txtHashVal = ((txtHashVal % mod) * (radix % mod)) % mod;
if (j + m2 < m1) {
txtHashVal = ((txtHashVal % mod) + (txtHash[j + m2] % mod)) % mod;
}
}
if (i < n1 - n2) {
// Calculate hash for next set of rows
ColRollingHash(txt, txtHash, i, n2, rowPow, mod, radix);
}
}
return res;
}
// Driver Code
static void Main() {
char[][] txt = {
new char[] { 'G', 'H', 'I', 'P' },
new char[] { 'J', 'K', 'L', 'Q' },
new char[] { 'R', 'G', 'H', 'I' },
new char[] { 'S', 'J', 'K', 'L' }
};
char[][] pat = {
new char[] { 'G', 'H', 'I' },
new char[] { 'J', 'K', 'L' }
};
List<int[]> res = SearchPattern(txt, pat);
foreach (int[] r in res) {
Console.Write("[" + r[0] + ", " + r[1] + "] ");
}
}
}
` JavaScript ``
// JavaScript program to implement Rabin-Karp Algorithm // for pattern searching in a 2-D matrix.
function findPower(a, n, mod) { if (n === 0) { return 1; } if (n === 1) { return a % mod; } let pow = findPower(a, Math.floor(n / 2), mod); if (n & 1) { return ((a % mod) * (pow % mod) * (pow % mod)) % mod; } else { return ((pow % mod) * (pow % mod)) % mod; } }
function findHash(mat, row, mod, radix) { let hash = []; let col = mat[0].length; for (let i = 0; i < col; i++) { let h = 0; for (let j = 0; j < row; j++) { h = (((h * radix) % mod) + (mat[j][i].charCodeAt(0) % mod)) % mod; } hash.push(h); } return hash; }
function check(txt, pat, r, c) { for (let i = 0; i < pat.length; i++) { for (let j = 0; j < pat[0].length; j++) { if (pat[i][j] !== txt[i + r][j + c]) { return false; } } } return true; }
function colRollingHash(txt, txtHash, row, n2, rowPow, mod, radix) { for (let i = 0; i < txtHash.length; i++) { txtHash[i] = (txtHash[i] % mod - ((txt[row][i].charCodeAt(0) % mod) * (rowPow % mod)) % mod + mod) % mod; txtHash[i] = ((txtHash[i] % mod) * (radix % mod)) % mod; txtHash[i] = ((txtHash[i] % mod) + (txt[row + n2][i].charCodeAt(0) % mod)) % mod; } }
function searchPattern(txt, pat) { let n1 = txt.length, m1 = txt[0].length; let n2 = pat.length, m2 = pat[0].length;
let mod = 257, radix = 256;
let res = [];
let rowPow = findPower(radix, n2 - 1, mod);
let colPow = findPower(radix, m2 - 1, mod);
let txtHash = findHash(txt, n2, mod, radix);
let patHash = findHash(pat, n2, mod, radix);
let patHashVal = 0;
for (let i = 0; i < m2; i++) {
patHashVal = (patHashVal * radix + patHash[i]) % mod;
}
for (let i = 0; i <= n1 - n2; i++) {
let txtHashVal = 0;
for (let j = 0; j < m2; j++) {
txtHashVal = (txtHashVal * radix + txtHash[j]) % mod;
}
for (let j = 0; j <= m1 - m2; j++) {
if (txtHashVal === patHashVal) {
if (check(txt, pat, i, j)) {
res.push([i, j]);
}
}
txtHashVal = (txtHashVal % mod - ((txtHash[j] % mod) * (colPow % mod)) % mod + mod) % mod;
txtHashVal = ((txtHashVal % mod) * (radix % mod)) % mod;
if (j + m2 < m1) {
txtHashVal = ((txtHashVal % mod) + (txtHash[j + m2] % mod)) % mod;
}
}
if (i < n1 - n2) {
colRollingHash(txt, txtHash, i, n2, rowPow, mod, radix);
}
}
return res;
}
// Driver code let txt = [ ['G', 'H', 'I', 'P'], ['J', 'K', 'L', 'Q'], ['R', 'G', 'H', 'I'], ['S', 'J', 'K', 'L'] ]; let pat = [ ['G', 'H', 'I'], ['J', 'K', 'L'] ];
let res = searchPattern(txt, pat);
res.forEach(r => console.log([${r[0]}, ${r[1]}]
));
``
**Time Complexity: O(n2 * m2), where n is the number of rows and m is the number of columns.
The time complexity of findHash() is O(n * m), check is O(n * m), and colRollingHash is O(n). We are calling findHash() approximately n * m times, so overall time complexity is O( log(n) + n + n * m ( n * m )) or O(n2 * m2).
**Space Complexity: O(n), required to stores hashes for rows of both the matrices.