📜  子矩阵求和查询

📅  最后修改于: 2022-05-13 01:57:21.501000             🧑  作者: Mango

子矩阵求和查询

给定一个大小为 M x N 的矩阵,有大量查询来查找子矩阵和。查询的输入是求和的子矩阵的左上和右下索引。
如何预处理矩阵,以便可以在 O(1) 时间内执行子矩阵求和查询。
例子 :

tli :  Row number of top left of query submatrix
tlj :  Column number of top left of query submatrix
rbi :  Row number of bottom right of query submatrix
rbj :  Column number of bottom right of query submatrix

Input: mat[M][N] = {{1, 2, 3, 4, 6},
                    {5, 3, 8, 1, 2},
                    {4, 6, 7, 5, 5},
                    {2, 4, 8, 9, 4} };
Query1: tli = 0, tlj = 0, rbi = 1, rbj = 1
Query2: tli = 2, tlj = 2, rbi = 3, rbj = 4
Query3: tli = 1, tlj = 2, rbi = 3, rbj = 3;

Output:
Query1: 11  // Sum between (0, 0) and (1, 1)
Query2: 38  // Sum between (2, 2) and (3, 4)
Query3: 38  // Sum between (1, 2) and (3, 3)

我们强烈建议您最小化您的浏览器并首先自己尝试。
这个想法是首先创建一个辅助矩阵 aux[M][N]使得 aux[i][j] 存储子矩阵中从 (0,0) 到 (i,j) 的元素总和。一旦构建了 aux[][],我们就可以在 O(1) 时间内计算 (tli, tlj) 和 (rbi, rbj) 之间的子矩阵之和。我们需要考虑 aux[rbi][rbj] 并减去所有不必要的元素。下面是在 O(1) 时间内计算子矩阵和的完整表达式。

Sum between (tli, tlj) and (rbi, rbj) is,
   aux[rbi][rbj] - aux[tli-1][rbj] - 
   aux[rbi][tlj-1] + aux[tli-1][tlj-1]

The submatrix aux[tli-1][tlj-1] is added because  
elements of it are subtracted twice.

插图:

mat[M][N] = {{1, 2, 3, 4, 6},
             {5, 3, 8, 1, 2},
             {4, 6, 7, 5, 5},
             {2, 4, 8, 9, 4} };

We first preprocess the matrix and build
following aux[M][N]
aux[M][N] = {1,  3,   6,  10, 16}
            {6,  11,  22, 27,  35},
            {10, 21,  39, 49,  62},  
            {12, 27,  53, 72,  89} }

Query : tli = 2, tlj = 2, rbi = 3, rbj = 4  
      
Sum between (2, 2) and (3, 4) = 89 - 35 - 27 + 11
                              = 38
         

如何构建 aux[M][N]?
1.将mat[][]的第一行复制到aux[][]
2. 对矩阵进行逐列求和并存储。
3. 在步骤 2 中对更新的矩阵 aux[][] 进行逐行求和。
下面是基于上述思想的程序。

C++
// C++ program to compute submatrix query sum in O(1)
// time
#include
using namespace std;
#define M 4
#define N 5
 
// Function to preprocess input mat[M][N].  This function
// mainly fills aux[M][N] such that aux[i][j] stores sum
// of elements from (0,0) to (i,j)
int preProcess(int mat[M][N], int aux[M][N])
{
   // Copy first row of mat[][] to aux[][]
   for (int i=0; i 0)
       res = res - aux[tli-1][rbj];
 
    // Remove elements between (0, 0) and (rbi, tlj-1)
    if (tlj > 0)
       res = res - aux[rbi][tlj-1];
 
    // Add aux[tli-1][tlj-1] as elements between (0, 0)
    // and (tli-1, tlj-1) are subtracted twice
    if (tli > 0 && tlj > 0)
       res = res + aux[tli-1][tlj-1];
 
    return res;
}
 
// Driver program
int main()
{
   int mat[M][N] = {{1, 2, 3, 4, 6},
                    {5, 3, 8, 1, 2},
                    {4, 6, 7, 5, 5},
                    {2, 4, 8, 9, 4} };
   int aux[M][N];
 
   preProcess(mat, aux);
 
   int tli = 2, tlj = 2, rbi = 3, rbj = 4;
   cout << "\nQuery1: " << sumQuery(aux, tli, tlj, rbi, rbj);
 
   tli = 0, tlj = 0, rbi = 1, rbj = 1;
   cout << "\nQuery2: " << sumQuery(aux, tli, tlj, rbi, rbj);
 
   tli = 1, tlj = 2, rbi = 3, rbj = 3;
   cout << "\nQuery3: " << sumQuery(aux, tli, tlj, rbi, rbj);
 
   return 0;
}


Java
// Java program to compute submatrix query
// sum in O(1) time
class GFG {
     
    static final int M = 4;
    static final int N = 5;
     
    // Function to preprocess input mat[M][N].
    // This function mainly fills aux[M][N]
    // such that aux[i][j] stores sum of
    // elements from (0,0) to (i,j)
    static int preProcess(int mat[][], int aux[][])
    {
         
        // Copy first row of mat[][] to aux[][]
        for (int i = 0; i < N; i++)
            aux[0][i] = mat[0][i];
         
        // Do column wise sum
        for (int i = 1; i < M; i++)
            for (int j = 0; j < N; j++)
                aux[i][j] = mat[i][j] +
                                aux[i-1][j];
         
        // Do row wise sum
        for (int i = 0; i < M; i++)
            for (int j = 1; j < N; j++)
                aux[i][j] += aux[i][j-1];
                 
        return 0;
    }
     
    // A O(1) time function to compute sum
    // of submatrix between (tli, tlj) and
    // (rbi, rbj) using aux[][] which is
    // built by the preprocess function
    static int sumQuery(int aux[][], int tli,
                    int tlj, int rbi, int rbj)
    {
         
        // result is now sum of elements
        // between (0, 0) and (rbi, rbj)
        int res = aux[rbi][rbj];
     
        // Remove elements between (0, 0)
        // and (tli-1, rbj)
        if (tli > 0)
            res = res - aux[tli-1][rbj];
     
        // Remove elements between (0, 0)
        // and (rbi, tlj-1)
        if (tlj > 0)
            res = res - aux[rbi][tlj-1];
     
        // Add aux[tli-1][tlj-1] as elements
        // between (0, 0) and (tli-1, tlj-1)
        // are subtracted twice
        if (tli > 0 && tlj > 0)
            res = res + aux[tli-1][tlj-1];
     
        return res;
    }
     
    // Driver code
    public static void main (String[] args)
    {
        int mat[][] = {{1, 2, 3, 4, 6},
                       {5, 3, 8, 1, 2},
                       {4, 6, 7, 5, 5},
                       {2, 4, 8, 9, 4}};
                        
        int aux[][] = new int[M][N];
         
        preProcess(mat, aux);
         
        int tli = 2, tlj = 2, rbi = 3, rbj = 4;
        System.out.print("\nQuery1: "
            + sumQuery(aux, tli, tlj, rbi, rbj));
         
        tli = 0; tlj = 0; rbi = 1; rbj = 1;
        System.out.print("\nQuery2: "
            + sumQuery(aux, tli, tlj, rbi, rbj));
         
        tli = 1; tlj = 2; rbi = 3; rbj = 3;
        System.out.print("\nQuery3: "
            + sumQuery(aux, tli, tlj, rbi, rbj));
    }
}
 
// This code is contributed by Anant Agarwal.


Python3
# Python 3 program to compute submatrix
# query sum in O(1) time
 
M = 4
N = 5
 
# Function to preprocess input mat[M][N].
# This function mainly fills aux[M][N]
# such that aux[i][j] stores sum
# of elements from (0,0) to (i,j)
def preProcess(mat, aux):
     
    # Copy first row of mat[][] to aux[][]
    for i in range(0, N, 1):
        aux[0][i] = mat[0][i]
 
    # Do column wise sum
    for i in range(1, M, 1):
        for j in range(0, N, 1):
            aux[i][j] = mat[i][j] + aux[i - 1][j]
 
    # Do row wise sum
    for i in range(0, M, 1):
        for j in range(1, N, 1):
            aux[i][j] += aux[i][j - 1]
 
# A O(1) time function to compute sum of submatrix
# between (tli, tlj) and (rbi, rbj) using aux[][]
# which is built by the preprocess function
def sumQuery(aux, tli, tlj, rbi, rbj):
     
    # result is now sum of elements
    # between (0, 0) and (rbi, rbj)
    res = aux[rbi][rbj]
 
    # Remove elements between (0, 0)
    # and (tli-1, rbj)
    if (tli > 0):
        res = res - aux[tli - 1][rbj]
 
    # Remove elements between (0, 0)
    # and (rbi, tlj-1)
    if (tlj > 0):
        res = res - aux[rbi][tlj - 1]
 
    # Add aux[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 + aux[tli - 1][tlj - 1]
 
    return res
 
# Driver Code
if __name__ == '__main__':
    mat = [[1, 2, 3, 4, 6],
           [5, 3, 8, 1, 2],
           [4, 6, 7, 5, 5],
           [2, 4, 8, 9, 4]]
aux = [[0 for i in range(N)]
          for j in range(M)]
 
preProcess(mat, aux)
 
tli = 2
tlj = 2
rbi = 3
rbj = 4
print("Query1:", sumQuery(aux, tli, tlj, rbi, rbj))
 
tli = 0
tlj = 0
rbi = 1
rbj = 1
print("Query2:", sumQuery(aux, tli, tlj, rbi, rbj))
 
tli = 1
tlj = 2
rbi = 3
rbj = 3
print("Query3:", sumQuery(aux, tli, tlj, rbi, rbj))
 
# This code is contributed by
# Shashank_Sharma


C#
// C# program to compute submatrix
// query sum in O(1) time
using System;
 
class GFG
{
    static int M = 4;
    static int N = 5;
     
    // Function to preprocess input mat[M][N].
    // This function mainly fills aux[M][N]
    // such that aux[i][j] stores sum of
    // elements from (0,0) to (i,j)
    static int preProcess(int [,]mat, int [,]aux)
    {
        // Copy first row of mat[][] to aux[][]
        for (int i = 0; i < N; i++)
            aux[0,i] = mat[0,i];
         
        // Do column wise sum
        for (int i = 1; i < M; i++)
            for (int j = 0; j < N; j++)
                aux[i,j] = mat[i,j] + aux[i-1,j];
         
        // Do row wise sum
        for (int i = 0; i < M; i++)
            for (int j = 1; j < N; j++)
                aux[i,j] += aux[i,j-1];
                 
        return 0;
    }
     
    // A O(1) time function to compute sum
    // of submatrix between (tli, tlj) and
    // (rbi, rbj) using aux[][] which is
    // built by the preprocess function
    static int sumQuery(int [,]aux, int tli,
                        int tlj, int rbi, int rbj)
    {
        // result is now sum of elements
        // between (0, 0) and (rbi, rbj)
        int res = aux[rbi,rbj];
     
        // Remove elements between (0, 0)
        // and (tli-1, rbj)
        if (tli > 0)
            res = res - aux[tli-1,rbj];
     
        // Remove elements between (0, 0)
        // and (rbi, tlj-1)
        if (tlj > 0)
            res = res - aux[rbi,tlj-1];
     
        // Add aux[tli-1][tlj-1] as elements
        // between (0, 0) and (tli-1, tlj-1)
        // are subtracted twice
        if (tli > 0 && tlj > 0)
            res = res + aux[tli-1,tlj-1];
     
        return res;
    }
     
    // Driver code
    public static void Main ()
    {
        int [,]mat = {{1, 2, 3, 4, 6},
                      {5, 3, 8, 1, 2},
                      {4, 6, 7, 5, 5},
                      {2, 4, 8, 9, 4}};
                         
        int [,]aux = new int[M,N];
         
        preProcess(mat, aux);
         
        int tli = 2, tlj = 2, rbi = 3, rbj = 4;
         
        Console.Write("\nQuery1: " +
                      sumQuery(aux, tli, tlj, rbi, rbj));
         
        tli = 0; tlj = 0; rbi = 1; rbj = 1;
         
        Console.Write("\nQuery2: " +
                      sumQuery(aux, tli, tlj, rbi, rbj));
         
        tli = 1; tlj = 2; rbi = 3; rbj = 3;
         
        Console.Write("\nQuery3: " +
                      sumQuery(aux, tli, tlj, rbi, rbj));
    }
}
 
// This code is contributed by Sam007.


PHP
 0)
    $res = $res - $aux[$tli - 1][$rbj];
 
    // Remove elements between (0, 0)
    // and (rbi, tlj-1)
    if ($tlj > 0)
    $res = $res - $aux[$rbi][$tlj - 1];
 
    // Add aux[tli-1][tlj-1] as elements between (0, 0)
    // and (tli-1, tlj-1) are subtracted twice
    if ($tli > 0 && $tlj > 0)
    $res = $res + $aux[$tli - 1][$tlj - 1];
 
    return $res;
}
 
// Driver Code
$mat = array(array(1, 2, 3, 4, 6),
             array(5, 3, 8, 1, 2),
             array(4, 6, 7, 5, 5),
             array(2, 4, 8, 9, 4));
 
preProcess($mat, $aux);
 
$tli = 2;
$tlj = 2;
$rbi = 3;
$rbj = 4;
echo ("Query1: ");
echo(sumQuery($aux, $tli, $tlj, $rbi, $rbj));
 
$tli = 0;
$tlj = 0;
$rbi = 1;
$rbj = 1;
echo ("\nQuery2: ");
echo(sumQuery($aux, $tli, $tlj, $rbi, $rbj));
 
 
$tli = 1;
$tlj = 2;
$rbi = 3;
$rbj = 3;
echo ("\nQuery3: ");
echo(sumQuery($aux, $tli, $tlj, $rbi, $rbj));
 
// This code is contributed by Shivi_Aggarwal
?>


Javascript


输出:

Query1: 38
Query2: 11
Query3: 38