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 r
emove
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.