Open In App

Maximum sum among all (a x b) submatrices for given Q queries

Given a matrix mat[][] of size N x M and an array queries[] of size Q, containing (a, b) pairs. The task is to find the maximum sum among all (a x b) sub-matrices of the matrix mat[][].  

Note: The rows and columns of the sub-matrix must be contiguous.



Examples:

Input: N = 3, M = 4, Q = 1, queries[] = {(3, 2)}
           mat[][] = {{1, 2, 3, 9},  
                              {4, 5, 6, 2},  
                              {8, 3, 2, 6}}
          
Output: 28
Explanation
Here a = 3 and b = 2
The first 3×2 submatrix is:
1 2
4 5
8 3
The sum of elements in this is 23.
The second 3×2 submatrix is:
2 3
5 6
3 2
The sum of elements in this is 21.
The third 3×2 submatrix is:
3 9
6 2
2 6
The sum of elements in this is 28.
The maximum among these are 28.



Input: N = 3, M = 4, Q = 3, queries[] = {(1, 1), (2, 2), (3, 3)}
            mat[][] = {{1, 2, 3, 9},  
                               {4, 5, 6, 2},  
                              {8, 3, 2, 6}}
           
Output: 9 20 38

Naive Approach: The simplest approach to solve this problem is for each query, find sum of every sub-matrix and print the largest one.

Time Complexity: O(Q*(N*M)^2), where Q is the number of queries, N and M are the number of rows and columns of the matrix mat[][].
Auxiliary Space: O(1)

Efficient Approach: This problem can be solved by doing some pre-processing before answering all the queries. Follow the steps below to solve this problem:

Reference: https://www.geeksforgeeks.org/submatrix-sum-queries/amp/

Below is the implementation of the above approach:




// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
 
// Function to preprocess input mat[N][M].
// This function mainly fills dp[N][M]
// such that dp[i][j] stores sum
// of elements from (0, 0) to (i, j)
void preProcess(vector<vector<int>> &mat,
                vector<vector<int>> &dp,
                              int n, int m)
{
     
    // Copy first row of mat[][] to dp[][]
    for(int i = 0; i < m; i++)
    {
        dp[0][i] = mat[0][i];
    }
 
    // Do column wise sum
    for(int i = 1; i < n; i++)
    {
        for(int j = 0; j < m; j++)
        {
            dp[i][j] = dp[i - 1][j] + mat[i][j];
        }
    }
 
    // Do row wise sum
    for(int i = 0; i < n; i++)
    {
        for(int j = 1; j < m; j++)
        {
            dp[i][j] += dp[i][j - 1];
        }
    }
}
 
// A O(1) time function to compute sum of submatrix
// between (tli, tlj) and (rbi, rbj) using dp[][]
// which is built by the preprocess function
int sumQuery(vector<vector<int>> dp, int tli,
             int tlj, int rbi, int rbj)
{
     
    // Result is now sum of elements
    // between (0, 0) and (rbi, rbj)
    int res = dp[rbi][rbj];
 
    // Remove elements between (0, 0)
    // and (tli-1, rbj)
    if (tli > 0)
        res = res - dp[tli - 1][rbj];
 
    // Remove elements between (0, 0)
    // and (rbi, tlj-1)
    if (tlj > 0)
        res = res - dp[rbi][tlj - 1];
 
    // Add dp[tli-1][tlj-1] as elements
    // between (0, 0) and (tli-1, tlj-1)
    // are subtracted twice
    if (tli > 0 && tlj > 0)
        res = res + dp[tli - 1][tlj - 1];
 
    return res;
}
 
// Function to find the maximum sum
// among all (a x b) sub-matrices of the matrix
vector<int> maxSubMatrixSumQueries(vector<vector<int>> mat,
                                   int n, int m,
                                   vector<vector<int>> queries,
                                   int q)
{
    vector<vector<int> > dp(n, vector<int>(m));
     
    // Function call
    preProcess(mat, dp, n, m);
 
    vector<int> maxSum((int)queries.size());
 
    // Run a loop for finding
    // answer for all queries
    for(int qi = 0; qi < q; qi++)
    {
        for(int i = 0; i < n - queries[qi][0] + 1; i++)
        {
            for(int j = 0; j < m - queries[qi][1] + 1; j++)
            {
                maxSum[qi] = max(maxSum[qi],
                                 sumQuery(dp, i, j,
                                          i + queries[qi][0] - 1,
                                          j + queries[qi][1] - 1));
            }
        }
    }
    return maxSum;
}
 
// Driver Code
int main()
{
     
    // Given input
    int n = 3, m = 4;
    vector<vector<int> > mat = { { 1, 2, 3, 9 },
                                 { 4, 5, 6, 2 },
                                 { 8, 3, 2, 6 } };
     
    int Q = 3;
    vector<vector<int> >Queries = { { 1, 1 },
                                    { 2, 2 },
                                    { 3, 3 } };
     
    // Function call
    vector<int> maxSum = maxSubMatrixSumQueries(
          mat, n, m, Queries, Q);
     
    // Print answer for all queries
    for(int i = 0; i < Q; i++)
    {
        cout << maxSum[i] << " ";
    }
}
 
// This code is contributed by mohit kumar 29




// Java program for the above approach
 
public class Solution {
 
    // Function to preprocess input mat[N][M].
    // This function mainly fills dp[N][M]
    // such that dp[i][j] stores sum
    // of elements from (0, 0) to (i, j)
    static void preProcess(int mat[][], int dp[][],
                           int n, int m)
    {
 
        // Copy first row of mat[][] to dp[][]
        for (int i = 0; i < m; i++) {
 
            dp[0][i] = mat[0][i];
        }
 
        // Do column wise sum
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < m; j++) {
 
                dp[i][j] = dp[i - 1][j] + mat[i][j];
            }
        }
 
        // Do row wise sum
        for (int i = 0; i < n; i++) {
            for (int j = 1; j < m; j++) {
 
                dp[i][j] += dp[i][j - 1];
            }
        }
    }
 
    // A O(1) time function to compute sum of submatrix
    // between (tli, tlj) and (rbi, rbj) using dp[][]
    // which is built by the preprocess function
    static int sumQuery(int dp[][], int tli,
                        int tlj, int rbi,
                        int rbj)
    {
 
        // Result is now sum of elements
        // between (0, 0) and (rbi, rbj)
        int res = dp[rbi][rbj];
 
        // Remove elements between (0, 0)
        // and (tli-1, rbj)
        if (tli > 0)
            res = res - dp[tli - 1][rbj];
 
        // Remove elements between (0, 0)
        // and (rbi, tlj-1)
        if (tlj > 0)
            res = res - dp[rbi][tlj - 1];
 
        // Add dp[tli-1][tlj-1] as elements
        // between (0, 0) and (tli-1, tlj-1)
        // are subtracted twice
        if (tli > 0 && tlj > 0)
            res
                = res + dp[tli - 1][tlj - 1];
 
        return res;
    }
 
    // Function to find the maximum sum
    // among all (a x b) sub-matrices of the matrix
    static int[] maxSubMatrixSumQueries(
        int[][] mat,
        int n, int m,
        int[][] queries,
        int q)
    {
 
        int dp[][] = new int[n][m];
 
        // Function call
        preProcess(mat, dp, n, m);
 
        int maxSum[] = new int[queries.length];
 
        // Run a loop for finding
        // answer for all queries
        for (int qi = 0; qi < q; qi++) {
 
            for (int i = 0; i < n - queries[qi][0] + 1; i++) {
                for (int j = 0; j < m - queries[qi][1] + 1; j++) {
                    maxSum[qi]
                        = Math.max(maxSum[qi],
                                   sumQuery(dp, i, j,
                                            i + queries[qi][0] - 1,
                                            j + queries[qi][1] - 1));
                }
            }
        }
 
        return maxSum;
    }
 
    // Driver Code
    public static void main(String args[])
    {
 
        // Given input
        int n = 3, m = 4;
        int mat[][] = { { 1, 2, 3, 9 },
                        { 4, 5, 6, 2 },
                        { 8, 3, 2, 6 } };
 
        int Q = 3;
        int Queries[][] = { { 1, 1 },
                            { 2, 2 },
                            { 3, 3 } };
 
        // Function call
        int maxSum[]
            = maxSubMatrixSumQueries(
                mat, n, m, Queries, Q);
 
        // Print answer for all queries
        for (int i = 0; i < Q; i++) {
            System.out.print(maxSum[i] + " ");
        }
    }
}




# Python program for the above approach
 
# Function to preprocess input mat[N][M].
# This function mainly fills dp[N][M]
# such that dp[i][j] stores sum
# of elements from (0, 0) to (i, j)
def preProcess(mat,  dp, n,  m):
 
    # Copy first row of mat[][] to dp[][]
    for i in range(m):
        dp[0][i] = mat[0][i]
 
    # Do column wise sum
    for i in range(1, n):
        for j in range(m):
            dp[i][j] = dp[i - 1][j] + mat[i][j]
 
    # Do row wise sum
    for i in range(n):
        for j in range(1, m):
            dp[i][j] += dp[i][j - 1]
 
 
# A O(1) time function to compute sum of submatrix
# between (tli, tlj) and (rbi, rbj) using dp[][]
# which is built by the preprocess function
def sumQuery(dp,  tli, tlj,  rbi, rbj):
    # Result is now sum of elements
    # between (0, 0) and (rbi, rbj)
    res = dp[rbi][rbj]
 
    # Remove elements between (0, 0)
    # and (tli-1, rbj)
    if (tli > 0):
        res = res - dp[tli - 1][rbj]
 
    # Remove elements between (0, 0)
    # and (rbi, tlj-1)
    if (tlj > 0):
        res = res - dp[rbi][tlj - 1]
 
    # Add dp[tli-1][tlj-1] as elements
    # between (0, 0) and (tli-1, tlj-1)
    # are subtracted twice
    if (tli > 0 and tlj > 0):
        res = res + dp[tli - 1][tlj - 1]
 
    return res
 
 
# Function to find the maximum sum
# among all (a x b) sub-matrices of the matrix
def maxSubMatrixSumQueries(mat, n,  m, queries, q):
    dp = [[0 for i in range(m)] for j in range(n)]
 
    # Function call
    preProcess(mat, dp, n, m)
    maxSum = [0]*len(queries)
 
    # Run a loop for finding
    # answer for all queries
    for qi in range(q):
        for i in range(n - queries[qi][0] + 1):
            for j in range(m - queries[qi][1] + 1):
                maxSum[qi] = max(maxSum[qi], sumQuery(dp, i, j,
                                                      i + queries[qi][0] - 1,
                                                      j + queries[qi][1] - 1))
    return maxSum
 
# Driver Code
 
# Given input
n = 3
m = 4
mat = [[1, 2, 3, 9],
       [4, 5, 6, 2],
       [8, 3, 2, 6]]
 
Q = 3
Queries = [[1, 1],
           [2, 2],
           [3, 3]]
 
# Function call
maxSum = maxSubMatrixSumQueries(mat, n, m, Queries, Q)
 
# Print answer for all queries
print(*maxSum)
 
# This code is comntributed by Lovely Jain




using System;
 
public class GFG{
     
    // Function to preprocess input mat[N][M].
    // This function mainly fills dp[N][M]
    // such that dp[i][j] stores sum
    // of elements from (0, 0) to (i, j)
    static void preProcess(int[,] mat, int[,] dp,
                           int n, int m)
    {
  
        // Copy first row of mat[][] to dp[][]
        for (int i = 0; i < m; i++) {
  
            dp[0,i] = mat[0,i];
        }
  
        // Do column wise sum
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < m; j++) {
  
                dp[i,j] = dp[i - 1,j] + mat[i,j];
            }
        }
  
        // Do row wise sum
        for (int i = 0; i < n; i++) {
            for (int j = 1; j < m; j++) {
  
                dp[i,j] += dp[i,j - 1];
            }
        }
    }
  
    // A O(1) time function to compute sum of submatrix
    // between (tli, tlj) and (rbi, rbj) using dp[][]
    // which is built by the preprocess function
    static int sumQuery(int[,] dp, int tli,
                        int tlj, int rbi,
                        int rbj)
    {
  
        // Result is now sum of elements
        // between (0, 0) and (rbi, rbj)
        int res = dp[rbi,rbj];
  
        // Remove elements between (0, 0)
        // and (tli-1, rbj)
        if (tli > 0)
            res = res - dp[tli - 1,rbj];
  
        // Remove elements between (0, 0)
        // and (rbi, tlj-1)
        if (tlj > 0)
            res = res - dp[rbi,tlj - 1];
  
        // Add dp[tli-1][tlj-1] as elements
        // between (0, 0) and (tli-1, tlj-1)
        // are subtracted twice
        if (tli > 0 && tlj > 0)
            res
                = res + dp[tli - 1,tlj - 1];
  
        return res;
    }
  
    // Function to find the maximum sum
    // among all (a x b) sub-matrices of the matrix
    static int[] maxSubMatrixSumQueries(
        int[,] mat,
        int n, int m,
        int[,] queries,
        int q)
    {
  
        int[,] dp = new int[n,m];
  
        // Function call
        preProcess(mat, dp, n, m);
  
        int[] maxSum = new int[queries.GetLength(0)];
  
        // Run a loop for finding
        // answer for all queries
        for (int qi = 0; qi < q; qi++) {
  
            for (int i = 0; i < n - queries[qi,0] + 1; i++) {
                for (int j = 0; j < m - queries[qi,1] + 1; j++) {
                    maxSum[qi]
                        = Math.Max(maxSum[qi],
                                   sumQuery(dp, i, j,
                                            i + queries[qi,0] - 1,
                                            j + queries[qi,1] - 1));
                }
            }
        }
  
        return maxSum;
    }
  
    // Driver Code
     
    static public void Main (){
         
         // Given input
        int n = 3, m = 4;
        int[,] mat = { { 1, 2, 3, 9 },
                        { 4, 5, 6, 2 },
                        { 8, 3, 2, 6 } };
  
        int Q = 3;
        int[,] Queries = { { 1, 1 },
                            { 2, 2 },
                            { 3, 3 } };
  
        // Function call
        int[] maxSum
            = maxSubMatrixSumQueries(
                mat, n, m, Queries, Q);
  
        // Print answer for all queries
        for (int i = 0; i < Q; i++) {
            Console.Write(maxSum[i] + " ");
        }
         
    }
}
 
// This code is contributed by patel2127.




<script>
 
// JavaScript program for the above approach
 
// Function to preprocess input mat[N][M].
// This function mainly fills dp[N][M]
// such that dp[i][j] stores sum
// of elements from (0, 0) to (i, j)
function preProcess(mat, dp, n, m)
{
     
    // Copy first row of mat[][] to dp[][]
    for(let i = 0; i < m; i++)
    {
        dp[0][i] = mat[0][i];
    }
 
    // Do column wise sum
    for(let i = 1; i < n; i++)
    {
        for(let j = 0; j < m; j++)
        {
            dp[i][j] = dp[i - 1][j] + mat[i][j];
        }
    }
 
    // Do row wise sum
    for(let i = 0; i < n; i++)
    {
        for(let j = 1; j < m; j++)
        {
            dp[i][j] += dp[i][j - 1];
        }
    }
}
 
// A O(1) time function to compute sum of submatrix
// between (tli, tlj) and (rbi, rbj) using dp[][]
// which is built by the preprocess function
function sumQuery(dp, tli, tlj, rbi, rbj)
{
     
    // Result is now sum of elements
    // between (0, 0) and (rbi, rbj)
    let res = dp[rbi][rbj];
 
    // Remove elements between (0, 0)
    // and (tli-1, rbj)
    if (tli > 0)
        res = res - dp[tli - 1][rbj];
 
    // Remove elements between (0, 0)
    // and (rbi, tlj-1)
    if (tlj > 0)
        res = res - dp[rbi][tlj - 1];
 
    // Add dp[tli-1][tlj-1] as elements
    // between (0, 0) and (tli-1, tlj-1)
    // are subtracted twice
    if (tli > 0 && tlj > 0)
        res = res + dp[tli - 1][tlj - 1];
 
    return res;
}
 
// Function to find the maximum sum
// among all (a x b) sub-matrices of the matrix
function maxSubMatrixSumQueries(mat, n, m, queries, q)
{
    let dp = Array(n).fill().map(() => Array(m));
 
    // Function call
    preProcess(mat, dp, n, m);
 
    let maxSum = new Array(queries.length).fill(0);
 
    // Run a loop for finding
    // answer for all queries
    for(let qi = 0; qi < q; qi++)
    {
        for(let i = 0; i < n - queries[qi][0] + 1; i++)
        {
            for(let j = 0; j < m - queries[qi][1] + 1; j++)
            {
                maxSum[qi] = Math.max(maxSum[qi],
                    sumQuery(dp, i, j,
                             i + queries[qi][0] - 1,
                             j + queries[qi][1] - 1));
            }
        }
    }
    return maxSum;
}
 
// Driver code
 
// Given input
let n = 3, m = 4;
let mat = [ [ 1, 2, 3, 9 ],
            [ 4, 5, 6, 2 ],
            [ 8, 3, 2, 6 ] ];
 
let Q = 3;
let Queries = [ [ 1, 1 ],
                [ 2, 2 ],
                [ 3, 3 ] ];
 
// Function call
let maxSum = maxSubMatrixSumQueries(
    mat, n, m, Queries, Q);
 
// Print answer for all queries
for(let i = 0; i < Q; i++)
{
    document.write(maxSum[i] + " ");
}
 
// This code is contributed by Potta Lokesh
 
</script>

Output
9 20 38 

Time Complexity: O(Q*N*M), where Q is the number of queries, N and M are the number of rows and columns of the matrix mat[][].
Auxiliary Space: O(N*M)


Article Tags :