Given a matrix mat[][] of size N*M, the task is to find the minimum value in a submatrix of the array, defined by the top-left and bottom-right indices of the submatrix for the given queries.
Example:
Input: N = 4, M = 4, mat[][] = { { 5, 8, 2, 4 }, { 7, 2, 9, 1 }, { 1, 4, 7, 3 }, { 3, 5, 6, 8 } }
queries[][] = {{0, 0, 3, 3}, {1, 1, 2, 2}}
Output:
1
2
Explanation:
For first query, top-left corner at (0, 0) and bottom-right corner at (2, 2), which is the entire input matrix. The minimum value in this submatrix is 1.
For second call, the top-left corner at (1, 1) and bottom-right corner at (2, 2). The minimum value in this submatrix is 2.
One solution to this problem is to use a data structure called a sparse table. A sparse table is a data structure that allows you to perform RMQ in O(1) time after O(nmlogn*logm) preprocessing time.
To build a sparse table for a 2D array, you can follow these steps:
- Preprocess the array to calculate the minimum value for each cell and for each submatrix with a size of 2k * 2l, where k and l are non-negative integers.
- Store the minimum values in a 2D array called the sparse table. The size of the sparse table should be n*m*log(n)*log(m).
- Firstly find the largest value of k such that 2k is less than or equal to the width of the submatrix.
- Then, find the largest value of l such that 2lis less than or equal to the height of the submatrix.
- Using these values, you can look up the minimum value in the sparse table and return it as the result.
Here is a brief example of how to implement a 2D range minimum query using a sparse table in Python:
// C++ code to implement the sparse table #include <bits/stdc++.h> using namespace std;
const int N = 100;
int matrix[N][N];
int table[N][N][( int )(log2(N) + 1)][( int )(log2(N) + 1)];
// Function to build the sparse table void build_sparse_table( int n, int m)
{ // Copy the values of the original matrix
// to the first element of the table
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < m; j++) {
table[i][j][0][0] = matrix[i][j];
}
}
// Building the table
for ( int k = 1; k <= ( int )(log2(n)); k++) {
for ( int i = 0; i + (1 << k) - 1 < n; i++) {
for ( int j = 0; j + (1 << k) - 1 < m; j++) {
table[i][j][k][0] = min(
table[i][j][k - 1][0],
table[i + (1 << (k - 1))][j][k - 1][0]);
}
}
}
for ( int k = 1; k <= ( int )(log2(m)); k++) {
for ( int i = 0; i < n; i++) {
for ( int j = 0; j + (1 << k) - 1 < m; j++) {
table[i][j][0][k] = min(
table[i][j][0][k - 1],
table[i][j + (1 << (k - 1))][0][k - 1]);
}
}
}
for ( int k = 1; k <= ( int )(log2(n)); k++) {
for ( int l = 1; l <= ( int )(log2(m)); l++) {
for ( int i = 0; i + (1 << k) - 1 < n; i++) {
for ( int j = 0; j + (1 << l) - 1 < m; j++) {
table[i][j][k][l] = min(
min(table[i][j][k - 1][l - 1],
table[i + (1 << (k - 1))][j]
[k - 1][l - 1]),
min(table[i][j + (1 << (l - 1))]
[k - 1][l - 1],
table[i + (1 << (k - 1))]
[j + (1 << (l - 1))][k - 1]
[l - 1]));
}
}
}
}
} // Function to find the maximum value in a submatrix int rmq( int x1, int y1, int x2, int y2)
{ // log2(x2-x1+1) gives the power of 2
// which is just less than or equal to x2-x1+1
int k = log2(x2 - x1 + 1);
int l = log2(y2 - y1 + 1);
// Lookup the value from the table which is
// the maximum among the 4 submatrices
return max(max(table[x1][y1][k][l],
table[x2 - (1 << k) + 1][y1][k][l]),
max(table[x1][y2 - (1 << l) + 1][k][l],
table[x2 - (1 << k) + 1]
[y2 - (1 << l) + 1][k][l]));
} // Function to solve the queries void solve( int n, int m, vector<vector< int > >& matrix1,
int q, vector< int > queries[])
{ int i = 0;
while (i < n) {
int j = 0;
while (j < m) {
matrix[i][j] = matrix1[i][j];
j++;
}
i++;
}
build_sparse_table(n, m);
i = 0;
while (i < q) {
int x1, y1, x2, y2;
x1 = queries[i][0];
y1 = queries[i][1];
x2 = queries[i][2];
y2 = queries[i][3];
cout << rmq(x1, y1, x2, y2) << endl;
i++;
}
} // Driver code int main()
{ int N = 4, M = 4;
vector<vector< int > > matrix1 = { { 5, 8, 2, 4 },
{ 7, 2, 9, 1 },
{ 1, 4, 7, 3 },
{ 3, 5, 6, 8 } };
int Q = 2;
vector< int > queries[]
= { { 0, 0, 3, 3 }, { 1, 1, 2, 2 } };
// Function call
solve(N, M, matrix1, Q, queries);
return 0;
} |
// Java code to implement the sparse table import java.util.Scanner;
class GFG {
static final int N = 100 ;
static int [][] matrix = new int [N][N];
static int [][][][] table
= new int [N][N]
[( int )(Math.log(N) / Math.log( 2 ) + 1 )]
[( int )(Math.log(N) / Math.log( 2 ) + 1 )];
// Function to build the sparse table
static void buildSparseTable( int n, int m)
{
// Copy the values of the original matrix
// to the first element of the table
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j < m; j++) {
table[i][j][ 0 ][ 0 ] = matrix[i][j];
}
}
// Building the table
for ( int k = 1 ;
k <= ( int )(Math.log(n) / Math.log( 2 )); k++) {
for ( int i = 0 ; i + ( 1 << k) - 1 < n; i++) {
for ( int j = 0 ; j + ( 1 << k) - 1 < m; j++) {
table[i][j][k][ 0 ]
= Math.min(table[i][j][k - 1 ][ 0 ],
table[i + ( 1 << (k - 1 ))]
[j][k - 1 ][ 0 ]);
}
}
}
for ( int k = 1 ;
k <= ( int )(Math.log(m) / Math.log( 2 )); k++) {
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j + ( 1 << k) - 1 < m; j++) {
table[i][j][ 0 ][k] = Math.min(
table[i][j][ 0 ][k - 1 ],
table[i][j + ( 1 << (k - 1 ))][ 0 ]
[k - 1 ]);
}
}
}
for ( int k = 1 ;
k <= ( int )(Math.log(n) / Math.log( 2 )); k++) {
for ( int l = 1 ;
l <= ( int )(Math.log(m) / Math.log( 2 ));
l++) {
for ( int i = 0 ; i + ( 1 << k) - 1 < n; i++) {
for ( int j = 0 ; j + ( 1 << l) - 1 < m;
j++) {
table[i][j][k][l] = Math.min(
Math.min(
table[i][j][k - 1 ][l - 1 ],
table[i + ( 1 << (k - 1 ))][j]
[k - 1 ][l - 1 ]),
Math.min(
table[i][j + ( 1 << (l - 1 ))]
[k - 1 ][l - 1 ],
table[i + ( 1 << (k - 1 ))]
[j + ( 1 << (l - 1 ))]
[k - 1 ][l - 1 ]));
}
}
}
}
}
// Function to find the maximum value in a submatrix
static int rmq( int x1, int y1, int x2, int y2)
{
// log2(x2-x1+1) gives the power of 2
// which is just less than or equal to x2-x1+1
int k = ( int )(Math.log(x2 - x1 + 1 ) / Math.log( 2 ));
int l = ( int )(Math.log(y2 - y1 + 1 ) / Math.log( 2 ));
// Lookup the value from the table which is
// the maximum among the 4 submatrices
return Math.max(
Math.max(table[x1][y1][k][l],
table[x2 - ( 1 << k) + 1 ][y1][k][l]),
Math.max(table[x1][y2 - ( 1 << l) + 1 ][k][l],
table[x2 - ( 1 << k) + 1 ]
[y2 - ( 1 << l) + 1 ][k][l]));
}
// Function to solve the queries
static void solve( int n, int m, int [][] matrix1, int q,
int [][] queries)
{
for ( int i = 0 ; i < n; i++) {
for ( int j = 0 ; j < m; j++) {
matrix[i][j] = matrix1[i][j];
}
}
buildSparseTable(n, m);
for ( int i = 0 ; i < q; i++) {
int x1, y1, x2, y2;
x1 = queries[i][ 0 ];
y1 = queries[i][ 1 ];
x2 = queries[i][ 2 ];
y2 = queries[i][ 3 ];
System.out.println(rmq(x1, y1, x2, y2));
}
}
// Driver code
public static void main(String[] args)
{
int N = 4 , M = 4 ;
int [][] matrix1 = { { 5 , 8 , 2 , 4 },
{ 7 , 2 , 9 , 1 },
{ 1 , 4 , 7 , 3 },
{ 3 , 5 , 6 , 8 } };
int Q = 2 ;
int [][] queries
= { { 0 , 0 , 3 , 3 }, { 1 , 1 , 2 , 2 } };
// Function call
solve(N, M, matrix1, Q, queries);
}
} // This Code is Contributed by Prasad Kandekar(prasad264) |
# Python code to implement the sparse table import math
N = 100
matrix = [[ 0 for j in range (N)] for i in range (N)]
table = [[[[ 0 for l in range ( int (math.log2(N)) + 1 )] for k in range (
int (math.log2(N)) + 1 )] for j in range (N)] for i in range (N)]
# Function to build the sparse table def build_sparse_table(n, m):
# Copy the values of the original matrix
# to the first element of the table
for i in range (n):
for j in range (m):
table[i][j][ 0 ][ 0 ] = matrix[i][j]
# Building the table
for k in range ( 1 , int (math.log2(n)) + 1 ):
for i in range (n - ( 1 << k) + 1 ):
for j in range (m - ( 1 << k) + 1 ):
table[i][j][k][ 0 ] = min (
table[i][j][k - 1 ][ 0 ], table[i + ( 1 << (k - 1 ))][j][k - 1 ][ 0 ])
for k in range ( 1 , int (math.log2(m)) + 1 ):
for i in range (n):
for j in range (m - ( 1 << k) + 1 ):
table[i][j][ 0 ][k] = min (
table[i][j][ 0 ][k - 1 ], table[i][j + ( 1 << (k - 1 ))][ 0 ][k - 1 ])
for k in range ( 1 , int (math.log2(n)) + 1 ):
for l in range ( 1 , int (math.log2(m)) + 1 ):
for i in range (n - ( 1 << k) + 1 ):
for j in range (m - ( 1 << l) + 1 ):
table[i][j][k][l] = min (
table[i][j][k - 1 ][l - 1 ],
table[i + ( 1 << (k - 1 ))][j][k - 1 ][l - 1 ],
table[i][j + ( 1 << (l - 1 ))][k - 1 ][l - 1 ],
table[i + ( 1 << (k - 1 ))][j + ( 1 << (l - 1 ))][k - 1 ][l - 1 ]
)
# Function to find the maximum value in a submatrix def rmq(x1, y1, x2, y2):
# log2(x2-x1+1) gives the power of 2 which is just less than or equal to x2-x1+1
k = int (math.log2(x2 - x1 + 1 ))
l = int (math.log2(y2 - y1 + 1 ))
# Lookup the value from the table which is the maximum among the 4 submatrices
return max (
table[x1][y1][k][l],
table[x2 - ( 1 << k) + 1 ][y1][k][l],
table[x1][y2 - ( 1 << l) + 1 ][k][l],
table[x2 - ( 1 << k) + 1 ][y2 - ( 1 << l) + 1 ][k][l]
)
# Function to solve the queries def solve(n, m, matrix1, q, queries):
for i in range (n):
for j in range (m):
matrix[i][j] = matrix1[i][j]
build_sparse_table(n, m)
for i in range (q):
x1, y1, x2, y2 = queries[i]
print (rmq(x1, y1, x2, y2))
N = 4
M = 4
matrix1 = [[ 5 , 8 , 2 , 4 ], [ 7 , 2 , 9 , 1 ], [ 1 , 4 , 7 , 3 ], [ 3 , 5 , 6 , 8 ]]
Q = 2
queries = [[ 0 , 0 , 3 , 3 ], [ 1 , 1 , 2 , 2 ]]
# Function call solve(N, M, matrix1, Q, queries) # This Code is Contributed by sankar. |
// C# code to implement the sparse table using System;
public class GFG {
const int N = 100;
static int [, ] matrix = new int [N, N];
static int [, , , ] table
= new int [N, N,
( int )(Math.Log(N) / Math.Log(2) + 1),
( int )(Math.Log(N) / Math.Log(2) + 1)];
// Function to build the sparse table
static void buildSparseTable( int n, int m)
{
// Copy the values of the original matrix
// to the first element of the table
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < m; j++) {
table[i, j, 0, 0] = matrix[i, j];
}
}
// Building the table
for ( int k = 1;
k <= ( int )(Math.Log(n) / Math.Log(2)); k++) {
for ( int i = 0; i + (1 << k) - 1 < n; i++) {
for ( int j = 0; j + (1 << k) - 1 < m; j++) {
table[i, j, k, 0]
= Math.Min(table[i, j, k - 1, 0],
table[i + (1 << (k - 1)),
j, k - 1, 0]);
}
}
}
for ( int k = 1;
k <= ( int )(Math.Log(m) / Math.Log(2)); k++) {
for ( int i = 0; i < n; i++) {
for ( int j = 0; j + (1 << k) - 1 < m; j++) {
table[i, j, 0, k] = Math.Min(
table[i, j, 0, k - 1],
table[i, j + (1 << (k - 1)), 0,
k - 1]);
}
}
}
for ( int k = 1;
k <= ( int )(Math.Log(n) / Math.Log(2)); k++) {
for ( int l = 1;
l <= ( int )(Math.Log(m) / Math.Log(2));
l++) {
for ( int i = 0; i + (1 << k) - 1 < n; i++) {
for ( int j = 0; j + (1 << l) - 1 < m;
j++) {
table[i, j, k, l] = Math.Min(
Math.Min(
table[i, j, k - 1, l - 1],
table[i + (1 << (k - 1)), j,
k - 1, l - 1]),
Math.Min(
table[i, j + (1 << (l - 1)),
k - 1, l - 1],
table[i + (1 << (k - 1)),
j + (1 << (l - 1)),
k - 1, l - 1]));
}
}
}
}
}
// Function to find the maximum value in a submatrix
static int rmq( int x1, int y1, int x2, int y2)
{
// log2(x2-x1+1) gives the power of 2
// which is just less than or equal to x2-x1+1
int k = ( int )(Math.Log(x2 - x1 + 1) / Math.Log(2));
int l = ( int )(Math.Log(y2 - y1 + 1) / Math.Log(2));
// Lookup the value from the table which is
// the maximum among the 4 submatrices
return Math.Max(
Math.Max(table[x1, y1, k, l],
table[x2 - (1 << k) + 1, y1, k, l]),
Math.Max(table[x1, y2 - (1 << l) + 1, k, l],
table[x2 - (1 << k) + 1,
y2 - (1 << l) + 1, k, l]));
}
// Function to solve the queries
static void solve( int n, int m, int [, ] matrix1, int q,
int [, ] queries)
{
for ( int i = 0; i < n; i++) {
for ( int j = 0; j < m; j++) {
matrix[i, j] = matrix1[i, j];
}
}
buildSparseTable(n, m);
for ( int i = 0; i < q; i++) {
int x1, y1, x2, y2;
x1 = queries[i, 0];
y1 = queries[i, 1];
x2 = queries[i, 2];
y2 = queries[i, 3];
Console.WriteLine(rmq(x1, y1, x2, y2));
}
}
static public void Main()
{
// Code
int N = 4, M = 4;
int [, ] matrix1 = { { 5, 8, 2, 4 },
{ 7, 2, 9, 1 },
{ 1, 4, 7, 3 },
{ 3, 5, 6, 8 } };
int Q = 2;
int [, ] queries
= { { 0, 0, 3, 3 }, { 1, 1, 2, 2 } };
// Function call
solve(N, M, matrix1, Q, queries);
}
} // This code is contributed by karthik. |
// Javascript code to implement the sparse table const N = 100; const matrix = new Array(N).fill( null ).map(() => new Array(N).fill(0));
const table = new Array(N).fill( null ).map(() => new Array(N).fill( null ).map(() => new Array(Math.ceil(Math.log2(N) + 1)).fill( null ).map(() => new Array(Math.ceil(Math.log2(N) + 1)).fill(0))));
// Function to build the sparse table function build_sparse_table(n, m) {
// Copy the values of the original matrix
// to the first element of the table
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
table[i][j][0][0] = matrix[i][j];
} }
// Building the table
for (let k = 1; k <= Math.log2(n); k++) {
for (let i = 0; i + (1 << k) - 1 < n; i++) {
for (let j = 0; j + (1 << k) - 1 < m; j++) {
table[i][j][k][0] = Math.min(
table[i][j][k - 1][0],
table[i + (1 << (k - 1))][j][k - 1][0]
);
}
} }
for (let k = 1; k <= Math.log2(m); k++) {
for (let i = 0; i < n; i++) {
for (let j = 0; j + (1 << k) - 1 < m; j++) {
table[i][j][0][k] = Math.min(
table[i][j][0][k - 1],
table[i][j + (1 << (k - 1))][0][k - 1]
);
}
} }
for (let k = 1; k <= Math.log2(n); k++) {
for (let l = 1; l <= Math.log2(m); l++) {
for (let i = 0; i + (1 << k) - 1 < n; i++) {
for (let j = 0; j + (1 << l) - 1 < m; j++) {
table[i][j][k][l] = Math.min(
Math.min(
table[i][j][k - 1][l - 1],
table[i + (1 << (k - 1))][j][k - 1][l - 1]
),
Math.min(
table[i][j + (1 << (l - 1))][k - 1][l - 1],
table[i + (1 << (k - 1))][j + (1 << (l - 1))][k - 1][l - 1]
)
);
}
}
} }
} // Function to find the maximum value in a submatrix function rmq(x1, y1, x2, y2)
{ // log2(x2-x1+1) gives the power of 2 // which is just less than or equal to x2-x1+1 let k = Math.ceil(Math.log2(x2 - x1 + 1)); let l = Math.ceil(Math.log2(y2 - y1 + 1)); // Lookup the value from the table which is // the maximum among the 4 submatrices return Math.max(Math.max(table[x1][y1][k][l],
table[x2 - (1 << k) + 1][y1][k][l]),
Math.max(table[x1][y2 - (1 << l) + 1][k][l],
table[x2 - (1 << k) + 1]
[y2 - (1 << l) + 1][k][l]));
} // Function to solve the queries function solve(n, m, matrix1,q, queries)
{ let i = 0; while (i < n) {
let j = 0;
while (j < m) {
matrix[i][j] = matrix1[i][j];
j++;
}
i++;
} build_sparse_table(n, m); i = 0; while (i < q) {
let x1, y1, x2, y2;
x1 = queries[i][0];
y1 = queries[i][1];
x2 = queries[i][2];
y2 = queries[i][3];
console.log(rmq(x1, y1, x2, y2)+ "<br>" )
i++;
} } // Driver code const n= 4, m = 4; const matrix1 = [[5, 8, 2, 4], [7, 2, 9, 1],
[1, 4, 7, 3],
[3, 5, 6, 8]];
const Q = 2; const queries = [[0, 0, 3, 3], [1, 1, 2, 2]]; // Function call solve(n, m, matrix1, Q, queries); // This code is contributed by Vaibhav. |
1 2
Time complexity:
- O(N * M * log(N) * log(M)) (To build sparse table)
- O(1) (For Each Query)
Auxiliary Space: O(N * M * log(N) * log(M))
Related Articles: