Open In App

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

Last Updated : 04 Jul, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

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:

  • Declare a 2D array, dp where dp[i][j] stores sum of elements from (0, 0) to (i, j).
  • Do some preprocessing for input mat[][]. Declare a function say, preProcess(mat, dp, n, m), do the following steps:
  • Declare an array, maxSum to store answer for each query.
  • Declare a function say, sumQuery(dp, tli, tlj, rbi, rbj), where tli and tlj are the row number and column number of top left of query submatrix respectively, rbi and rbj  are the row number and column number of bottom right of query submatrix, that compute sum of submatrix in O(1) time.
    • Initialize a variable res as dp[rbi][rbj] to store sum of the submatrix.
    • If tli is greater 0, then remove elements between (0, 0) and (tli-1, rbj).
    • If tlj is greater than 0, then remove elements between (0, 0) and (rbi, tlj-1).
    • If tli is greater than 0 and tlj is greater than 0, then add dp[tli-1][tlj-1] as elements between (0, 0) and (tli-1, tlj-1) are subtracted twice.
  • Iterate in the range [0, q-1] using the variable qi: 
    • Iterate in the range [0, n-queries[qi][0]] using the variable i:
      • Iterate in the range [0, m-queries[qi][1]] using the variable j: 
        • Update maxSum[qi] to max of maxSum[qi] and sumQuery(dp, i, j, i + queries[qi][0] – 1, j + queries[qi][1] – 1)).
  • After completing the above steps, print the array maxSum as the answer for each query.

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

Below is the implementation of the above approach:

C++




// 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




// 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] + " ");
        }
    }
}


Python3




# 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


C#




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.


Javascript




<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)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads