📜  给定 Q 查询的所有 (axb) 子矩阵之间的最大总和

📅  最后修改于: 2021-09-22 10:10:18             🧑  作者: Mango

给定大小为N x M的矩阵mat[][]和大小为Q的数组查询 [] 包含(a, b)对。任务是在矩阵mat[][] 的所有(axb)子矩阵中找到最大和。

例子:

朴素的方法:解决这个问题的最简单的方法是对每个查询,找到每个子矩阵的总和并打印最大的一个。

时间复杂度: O(Q*(N*M)^2),其中Q是查询次数, NM是矩阵mat[][]的行数和列数
辅助空间: O(1)

高效的方法:这个问题可以通过在回答所有查询之前做一些预处理来解决。请按照以下步骤解决此问题:

  • 声明一个二维数组dp ,其中dp[i][j]存储从(0, 0)(i, j)的元素总和
  • 对输入mat[][]进行一些预处理声明一个函数,例如preProcess(mat, dp, n, m),执行以下步骤:
    • 使用变量i在范围[0, m-1] 中迭代,并且 dp[0][i]更新为mat[0][i]。
    • 使用变量i在范围[1, n-1] 中迭代:  
      • 使用变量j在范围[0, m-1] 中迭代
        • dp[i][j]更新为dp[i-1][j] + mat[i][j]。
    • 使用变量i在范围[0, n-1] 中迭代:  
      • 使用变量j在范围[1, m-1] 中迭代
        • dp[i][j]更新为dp[i][j] + dp[i][j-1]。
  • 声明一个数组maxSum来存储每个查询的答案。
  • 声明一个函数, sumQuery(dp, tli, tlj, rbi, rbj),其中tlitlj分别是查询子矩阵左上角的行号和列号, rbirbj右下角的行号和列号查询子矩阵,在O(1)时间内计算子矩阵的总和。
    • 将变量res初始化为dp[rbi][rbj]以存储子矩阵的总和。
    • 如果tl i 大于0 ,则删除(0, 0)(tli-1, rbj)之间的元素。
    • 如果tlj大于0,则删除 (0, 0) 和 (rbi, tlj-1) 之间的元素。
    • 如果tli大于0tlj大于0,则添加dp[tli-1][tlj-1]作为(0, 0)(tli-1, tlj-1) 之间的元素减去两次。
  • 使用变量qi在范围[0, q-1] 中迭代:  
    • 使用变量i在范围[0, n-queries[qi][0]] 中迭代
      • 使用变量j在范围[0, m-queries[qi][1]] 中迭代:  
        • maxSum[qi]更新为maxSum[qi]sumQuery(dp, i, j, i + queries[qi][0] – 1, j + queries[qi][1] – 1)) 的最大值
  • 完成上述步骤后,打印数组maxSum作为每个查询的答案。

参考: https : //www.geeksforgeeks.org/submatrix-sum-queries/

下面是上述方法的实现:

C++
// C++ program for the above approach
#include 
using namespace std;
 
// Function to preprcess 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> &mat,
                vector> &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> 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 maxSubMatrixSumQueries(vector> mat,
                                   int n, int m,
                                   vector> queries,
                                   int q)
{
    vector > dp(n, vector(m));
     
    // Function call
    preProcess(mat, dp, n, m);
 
    vector 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 > mat = { { 1, 2, 3, 9 },
                                 { 4, 5, 6, 2 },
                                 { 8, 3, 2, 6 } };
     
    int Q = 3;
    vector >Queries = { { 1, 1 },
                                    { 2, 2 },
                                    { 3, 3 } };
     
    // Function call
    vector 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 preprcess 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] + " ");
        }
    }
}


C#
using System;
 
public class GFG{
     
    // Function to preprcess 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


输出
9 20 38 

时间复杂度: O(Q*N*M),其中Q是查询次数,N和M是矩阵mat[][]的行数和列数
辅助空间: O(N*M)

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程