Algorithm approach with sparse table: - <O( N x M x log(N) x log(M)) , O(1)> .
Precompression Time - O( N x M x log(N) x log(M))
Request Time - O(1)
To understand this method, you need to know how to find RMQ using the sparse Table Algorithm for a single dimension.
We can use the 2D sparse table algorithm to find the minimum range query.
What we do in one dimension: -
we pre-process RMQ for auxiliary arrays of length 2^k using dynamic programming. We will store the array M[0, N-1][0, logN] , where M[i][j] is the index of the minimum value in the basement, starting with i . To calculate M[i][j] we must look for the minimum value in the first and second half of the interval. Obviously, the small pieces are 2^(j β 1) long, so the pseudo-code for calculating this is: -
if (A[M[i][j-1]] < A[M[i + 2^(j-1) -1][j-1]]) M[i][j] = M[i][j-1] else M[i][j] = M[i + 2^(j-1) -1][j-1]
Here A is the actual array in which the values ββare stored. After that, we will pre-process these values, show how we can use them to calculate RMQ (i, j) . The idea is to select two blocks that completely cover the interval [i..j] and find the minimum between them. Let k = [log(j - i + 1)] . To calculate RMQ (i, j) we can use the following formula: -
if (A[M[i][k]] <= A[M[j - 2^k + 1][k]]) RMQ(i, j) = A[M[i][k]] else RMQ(i , j) = A[M[j - 2^k + 1][k]]
For 2 measurements: -
In the same way, we can extend the rule above for 2 Dimension, here we pre-process RMQ for a submatrix of length 2^K, 2^L using dynamic programming and save the array M[0,N-1][0, M-1][0, logN][0, logM] . Where M[x][y][k][l] is the index of the minimum value in the submatrix, starting with [x , y] and having a length of 2^K, 2^L respectively. pseudo code for calculating M[x][y][k][l] : -
M[x][y][i][j] = GetMinimum(M[x][y][i-1][j-1], M[x + (2^(i-1))][y][i-1][j-1], M[x][y+(2^(j-1))][i-1][j-1], M[x + (2^(i-1))][y+(2^(j-1))][i-1][j-1])
Here, the GetMinimum function returns the index of the minimum element from the provided elements. Now we have pre-processed, let's see how to calculate RMQ (x, y, x1, y1) . Here, [x, y] starting point of the submatrix and [x1, y1] represents the ending point of the submatrix, which means the lower right point of the submatrix. Here we must select four blocks of submatrices that completely cover [x, y, x1, y1] and find their minimum. Let k = [log(x1 - x + 1)] and l = [log(y1 - y + 1)] . To calculate RMQ (x, y, x1, y1) we can use the following formula: -
RMQ(x, y, x1, y1) = GetMinimum(M[x][y][k][l], M[x1 - (2^k) + 1][y][k][l], M[x][y1 - (2^l) + 1][k][l], M[x1 - (2^k) + 1][y1 - (2^l) + 1][k][l]);
pseudo code for logic above: -
// remember Array 'M' store index of actual matrix 'P' so for comparing values in GetMinimum function compare the values of array 'P' not of array 'M' SparseMatrix(n , m){ // n , m is dimension of matrix. for i = 0 to 2^i <= n: for j = 0 to 2^j <= m: for x = 0 to x + 2^i -1 < n : for y = 0 to y + (2^j) -1 < m: if i == 0 and j == 0: M[x][y][i][j] = Pair(x , y) // store x, y else if i == 0: M[x][y][i][j] = GetMinimum(M[x][y][i][j-1], M[x][y+(2^(j-1))][i][j-1]) else if j == 0: M[x][y][i][j] = GetMinimum(M[x][y][i-1][j], M[x+ (2^(i-1))][y][i-1][j]) else M[x][y][i][j] = GetMinimum(M[x][y][i-1][j-1], M[x + (2^(i-1))][y][i-1][j-1], M[x][y+(2^(j-1))][i-1][j-1], M[x + (2^(i-1))][y+(2^(j-1))][i-1][j-1]); } RMQ(x, y, x1, y1){ k = log(x1 - x + 1) l = log(y1 - y + 1) ans = GetMinimum(M[x][y][k][l], M[x1 - (2^k) + 1][y][k][l], M[x][y1 - (2^l) + 1][k][l], M[x1 - (2^k) + 1][y1 - (2^l) + 1][k][l]); return P[ans->x][ans->y] // ans->x represent Row number stored in ans and similarly ans->y represent column stored in ans }