Last Updated : 29 Jul, 2025
Try it on GfG Practice
The prefix sum of a matrix (or 2D array) is a powerful technique used to efficiently compute the sum of elements in a submatrix. Instead of recalculating the sum from scratch every time, we precompute a new matrix where each element contains the sum of a specific submatrix from the top-left corner to that cell.
This concept is an extension of 1D prefix sums and is commonly used in competitive programming and coding interviews.
What is a Prefix Sum Matrix?
A prefix sum matrix is a new matrix sum[][] where:
=> sum[i][j] represents the sum of all elements in the rectangle from (0,0) to (i-1,j-1) in the original matrix.
This allows for quick calculations of any submatrix sum using the inclusion-exclusion principle.
How to Construct the Prefix Sum Matrix
Given a matrix arr[][] of dimensions n × m, the prefix sum matrix sum[][] can be constructed as:
prefix[i][j] = arr[i][j] + prefix[i-1][j] + prefixi][j-1] - prefix[i-1][j-1]
Make sure to handle edge cases when i == 0 or j == 0.
C++
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> prefixSum2D(vector<vector<int>> &arr) {
// number of rows
int n = arr.size();
// number of columns
int m = arr[0].size();
vector<vector<int>> prefix(n, vector<int>(m, 0));
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// Start with original value
prefix[i][j] = arr[i][j];
// Add value from top cell if it exists
if (i > 0) {
prefix[i][j] += prefix[i - 1][j];
}
// Add value from left cell if it exists
if (j > 0) {
prefix[i][j] += prefix[i][j - 1];
}
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0) {
prefix[i][j] -= prefix[i - 1][j - 1];
}
}
}
return prefix;
}
int main() {
vector<vector<int>> arr = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}};
vector<vector<int>> prefix = prefixSum2D(arr);
for (int i = 0; i < prefix.size(); i++) {
for (int j = 0; j < prefix[0].size(); j++) {
cout << prefix[i][j] << " ";
}
cout << endl;
}
return 0;
}
Java
import java.util.ArrayList;
class GfG {
public static ArrayList<ArrayList<Integer>> prefixSum2D(int[][] arr) {
// number of rows
int n = arr.length;
// number of columns
int m = arr[0].length;
// Initialize prefix with 0s
ArrayList<ArrayList<Integer>> prefix = new ArrayList<>();
for (int i = 0; i < n; i++) {
prefix.add(new ArrayList<>());
for (int j = 0; j < m; j++) {
prefix.get(i).add(0);
}
}
// Compute prefix sum matrix
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
// Start with original value
int value = arr[i][j];
// Add value from top cell if it exists
if (i > 0) {
value += prefix.get(i - 1).get(j);
}
// Add value from left cell if it exists
if (j > 0) {
value += prefix.get(i).get(j - 1);
}
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0) {
value -= prefix.get(i - 1).get(j - 1);
}
prefix.get(i).set(j, value);
}
}
return prefix;
}
public static void main(String[] args) {
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
ArrayList<ArrayList<Integer>> prefix = prefixSum2D(arr);
for (ArrayList<Integer> row : prefix) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
}
}
Python
def prefixSum2D(arr):
# number of rows
n = len(arr)
# number of columns
m = len(arr[0])
# Initialize prefix with 0s
prefix = [[0] * m for _ in range(n)]
# Compute prefix sum matrix
for i in range(n):
for j in range(m):
# Start with original value
prefix[i][j] = arr[i][j]
# Add value from top cell if it exists
if i > 0:
prefix[i][j] += prefix[i - 1][j]
# Add value from left cell if it exists
if j > 0:
prefix[i][j] += prefix[i][j - 1]
# Subtract overlap from top-left diagonal if it exists
if i > 0 and j > 0:
prefix[i][j] -= prefix[i - 1][j - 1]
return prefix
if __name__ == "__main__":
arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
prefix = prefixSum2D(arr)
for row in prefix:
print(" ".join(map(str, row)))
C#
using System;
using System.Collections.Generic;
class GfG{
public static List<List<int>> PrefixSum2D(int[,] arr){
// number of rows
int n = arr.GetLength(0);
// number of columns
int m = arr.GetLength(1);
// initialize prefix matrix with 0s
List<List<int>> prefix = new List<List<int>>();
for (int i = 0; i < n; i++){
List<int> row = new List<int>();
for (int j = 0; j < m; j++){
row.Add(0);
}
prefix.Add(row);
}
for (int i = 0; i < n; i++){
for (int j = 0; j < m; j++){
// Start with original value
int val = arr[i, j];
// Add value from top cell if it exists
if (i > 0){
val += prefix[i - 1][j];
}
// Add value from left cell if it exists
if (j > 0){
val += prefix[i][j - 1];
}
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0){
val -= prefix[i - 1][j - 1];
}
prefix[i][j] = val;
}
}
return prefix;
}
static void Main(){
int[,] arr = {
{ 1, 2, 3, 4 },
{ 5, 6, 7, 8 },
{ 9, 10, 11, 12 },
{ 13, 14, 15, 16 }
};
List<List<int>> prefix = PrefixSum2D(arr);
foreach (var row in prefix){
foreach (var val in row){
Console.Write(val + " ");
}
Console.WriteLine();
}
}
}
JavaScript
function prefixSum2D(arr) {
// number of rows
const n = arr.length;
// number of columns
const m = arr[0].length;
// initialize prefix matrix with 0s
const prefix = Array.from({ length: n }, () => Array(m).fill(0));
for (let i = 0; i < n; i++) {
for (let j = 0; j < m; j++) {
// Start with original value
let val = arr[i][j];
// Add value from top cell if it exists
if (i > 0) {
val += prefix[i - 1][j];
}
// Add value from left cell if it exists
if (j > 0) {
val += prefix[i][j - 1];
}
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0) {
val -= prefix[i - 1][j - 1];
}
prefix[i][j] = val;
}
}
return prefix;
}
// Driver Code
const arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
];
const prefix = prefixSum2D(arr);
for (let row of prefix) {
console.log(row.join(" "));
}
1 3 6 10 6 14 24 36 15 33 54 78 28 60 96 136
How to Query Submatrix Sums Using Prefix Sum Matrix
Suppose we want the sum of all elements inside a submatrix from (r1, c1) to (r2, c2), then the result is:
C++prefix[r2][c2] - prefix[r1-1][c2] - prefix[r2][c1-1] + prefix[r1-1][c1-1]
#include <iostream>
#include <vector>
using namespace std;
vector<int> prefixSum2D(vector<vector<int>> &arr, vector<vector<int>> &queries) {
int n = arr.size();
int m = arr[0].size();
// Construct prefix sum matrix using 0-based indexing
vector<vector<int>> prefix(n, vector<int>(m, 0));
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
// Start with original value
prefix[i][j] = arr[i][j];
// Add value from top cell if it exists
if (i > 0)
prefix[i][j] += prefix[i - 1][j];
// Add value from left cell if it exists
if (j > 0)
prefix[i][j] += prefix[i][j - 1];
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0)
prefix[i][j] -= prefix[i - 1][j - 1];
}
}
vector<int> result;
// Process each query using inclusion-exclusion
for (auto &q : queries) {
int r1 = q[0], c1 = q[1];
int r2 = q[2], c2 = q[3];
int total = prefix[r2][c2];
int top = (r1 > 0) ? prefix[r1 - 1][c2] : 0;
int left = (c1 > 0) ? prefix[r2][c1 - 1] : 0;
int overlap = (r1 > 0 && c1 > 0) ? prefix[r1 - 1][c1 - 1] : 0;
int sum = total - top - left + overlap;
result.push_back(sum);
}
return result;
}
int main() {
vector<vector<int>> arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
vector<vector<int>> queries = {
{1, 1, 2, 2},
};
vector<int> result = prefixSum2D(arr, queries);
for (int sum : result) {
cout << sum << " ";
}
cout << endl;
}
Java
import java.util.ArrayList;
class GfG {
public static ArrayList<Integer> prefixSum2D(int[][] arr, int[][] queries) {
int n = arr.length;
int m = arr[0].length;
// Construct prefix sum matrix
int[][] prefix = new int[n][m];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
// Start with original value
prefix[i][j] = arr[i][j];
// Add value from top cell if it exists
if (i > 0)
prefix[i][j] += prefix[i - 1][j];
// Add value from left cell if it exists
if (j > 0)
prefix[i][j] += prefix[i][j - 1];
// Subtract overlap from top-left diagonal if it exists
if (i > 0 && j > 0)
prefix[i][j] -= prefix[i - 1][j - 1];
}
}
// Result list
ArrayList<Integer> result = new ArrayList<>();
// Process each query using inclusion-exclusion
for (int i = 0; i < queries.length; i++) {
int r1 = queries[i][0];
int c1 = queries[i][1];
int r2 = queries[i][2];
int c2 = queries[i][3];
int total = prefix[r2][c2];
if (r1 > 0)
total -= prefix[r1 - 1][c2];
if (c1 > 0)
total -= prefix[r2][c1 - 1];
if (r1 > 0 && c1 > 0)
total += prefix[r1 - 1][c1 - 1];
result.add(total);
}
return result;
}
public static void main(String[] args) {
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
int[][] queries = {
{1, 1, 2, 2}
};
ArrayList<Integer> result = prefixSum2D(arr, queries);
for (int sum : result) {
System.out.print(sum + " ");
}
System.out.println();
}
}
Python
def prefixSum2D(mat, queries):
rows = len(mat)
cols = len(mat[0])
# create prefix matrix of size (rows+1)x(cols+1)
# to simplify boundaries
pre = [[0] * (cols + 1) for _ in range(rows + 1)]
# Build prefix matrix with 1-based indexing
for i in range(1, rows + 1):
for j in range(1, cols + 1):
pre[i][j] = mat[i - 1][j - 1] \
+ pre[i - 1][j] \
+ pre[i][j - 1] \
- pre[i - 1][j - 1]
result = []
# process each query using inclusion-exclusion
for q in queries:
topRow = q[0] + 1
leftCol = q[1] + 1
bottomRow = q[2] + 1
rightCol = q[3] + 1
# get total area from (1,1) to (bottomRow, rightCol)
total = pre[bottomRow][rightCol]
# subtract area above the submatrix
top = pre[topRow - 1][rightCol]
# subtract area to the left of the submatrix
left = pre[bottomRow][leftCol - 1]
# add back the overlapping top-left area,
# which was subtracted twice
overlap = pre[topRow - 1][leftCol - 1]
# final submatrix sum using inclusion-exclusion
result.append(total - top - left + overlap)
return result
# Driver Code
if __name__ == "__main__":
mat = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
]
queries = [
[1, 1, 2, 2]
]
result = prefixSum2D(mat, queries)
print(" ".join(map(str, result)))
C#
using System;
using System.Collections.Generic;
class GfG {
public static List<int> prefixSum2D(int[,] arr, int[,] queries) {
// number of rows
int n = arr.GetLength(0);
// number of columns
int m = arr.GetLength(1);
// Construct prefix sum matrix using 0-based indexing
int[,] prefix = new int[n, m];
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
prefix[i, j] = arr[i, j];
if (i > 0)
prefix[i, j] += prefix[i - 1, j];
if (j > 0)
prefix[i, j] += prefix[i, j - 1];
if (i > 0 && j > 0)
prefix[i, j] -= prefix[i - 1, j - 1];
}
}
List<int> result = new List<int>();
int q = queries.GetLength(0);
for (int k = 0; k < q; k++) {
int r1 = queries[k, 0];
int c1 = queries[k, 1];
int r2 = queries[k, 2];
int c2 = queries[k, 3];
int total = prefix[r2, c2];
int top = (r1 > 0) ? prefix[r1 - 1, c2] : 0;
int left = (c1 > 0) ? prefix[r2, c1 - 1] : 0;
int overlap = (r1 > 0 && c1 > 0) ? prefix[r1 - 1, c1 - 1] : 0;
int sum = total - top - left + overlap;
result.Add(sum);
}
return result;
}
public static void Main() {
int[,] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12},
{13, 14, 15, 16}
};
int[,] queries = {
{1, 1, 2, 2}
};
List<int> result = prefixSum2D(arr, queries);
foreach (int sum in result) {
Console.Write(sum + " ");
}
Console.WriteLine();
}
}
JavaScript
function prefixSum2D(mat, queries) {
const rows = mat.length;
const cols = mat[0].length;
// create prefix matrix of size (rows+1)x(cols+1)
// to simplify boundaries
const pre = Array.from({ length: rows + 1 }, () =>
new Array(cols + 1).fill(0)
);
// Build prefix matrix with 1-based indexing
for (let i = 1; i <= rows; i++) {
for (let j = 1; j <= cols; j++) {
pre[i][j] = mat[i - 1][j - 1]
+ pre[i - 1][j]
+ pre[i][j - 1]
- pre[i - 1][j - 1];
}
}
const result = [];
// process each query using inclusion-exclusion
for (const q of queries) {
const topRow = q[0] + 1;
const leftCol = q[1] + 1;
const bottomRow = q[2] + 1;
const rightCol = q[3] + 1;
// get total area from (1,1) to (bottomRow, rightCol)
const total = pre[bottomRow][rightCol];
// subtract area above the submatrix
const top = pre[topRow - 1][rightCol];
// subtract area to the left of the submatrix
const left = pre[bottomRow][leftCol - 1];
// add back the overlapping top-left area,
// which was subtracted twice
const overlap = pre[topRow - 1][leftCol - 1];
// final submatrix sum using inclusion-exclusion
result.push(total - top - left + overlap);
}
return result;
}
// Driver Code
const mat = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
];
const queries = [
[1, 1, 2, 2]
];
const result = prefixSum2D(mat, queries);
console.log(result.join(' '));
Time Complexity: O(n × m + q), where n is the number of rows, m is the number of columns, and q is the number of queries. Each query is handled in O(1) time.
Auxiliary Space: O(n × m + q), where n is the number of rows, m is the number of columns (for storing the prefix sum matrix), and q is the number of queries (for storing the results).
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4