子矩阵求和查询
给定一个大小为 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