Skip to content

Commit 1117e1f

Browse files
committed
Add 2D Prefix Sum documentation
- Introduced a new Markdown file detailing the 2D Prefix Sum technique, including its summary, goal, and formula for creating a prefix sum matrix. - Provided code snippets for both functional and class-based implementations, along with a query function for efficient submatrix sum retrieval. - Included examples, edge cases, and validation to enhance understanding and practical application of the technique.
1 parent a65d17a commit 1117e1f

1 file changed

Lines changed: 176 additions & 0 deletions

File tree

‎notes/algo/2d-prefix-sum.md‎

Lines changed: 176 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,176 @@
1+
---
2+
title: "2D Prefix Sum"
3+
date: "2025-10-07"
4+
tags: []
5+
related: []
6+
slug: "2d-prefix-sum"
7+
category: "algo"
8+
---
9+
10+
# 2D Prefix Sum
11+
12+
## Summary
13+
2D Prefix Sum (summed-area table) is a preprocessing technique that allows O(1) time queries for the sum of any submatrix in a 2D array by precomputing cumulative sums, commonly used for efficient range sum queries in grid problems.
14+
15+
## Details
16+
### 🎯 Goal
17+
Given a matrix of size `m x n`, create a prefix_sum matrix where each cell `(i, j)` contains the sum of the submatrix from `(0, 0)` to `(i, j)`.
18+
19+
### ✅ Formula
20+
For cell `(i, j)` in the prefix sum matrix:
21+
22+
```python
23+
prefix_sum[i][j] = matrix[i][j]
24+
+ prefix_sum[i-1][j]
25+
+ prefix_sum[i][j-1]
26+
- prefix_sum[i-1][j-1]
27+
```
28+
29+
**Note:** The last term is subtracted to remove the double-counted area.
30+
31+
### 📍 To Query a Submatrix Sum (r1, c1) to (r2, c2)
32+
You can use the prefix sum to quickly get any submatrix sum in O(1) time:
33+
34+
```python
35+
def query_sum(prefix, r1, c1, r2, c2):
36+
total = prefix[r2][c2]
37+
if r1 > 0:
38+
total -= prefix[r1 - 1][c2]
39+
if c1 > 0:
40+
total -= prefix[r2][c1 - 1]
41+
if r1 > 0 and c1 > 0:
42+
total += prefix[r1 - 1][c1 - 1]
43+
return total
44+
```
45+
46+
## Examples / snippets
47+
48+
### Implementation in Python
49+
```python
50+
def compute_2d_prefix_sum(matrix):
51+
if not matrix or not matrix[0]:
52+
return []
53+
54+
m, n = len(matrix), len(matrix[0])
55+
prefix_sum = [[0]*n for _ in range(m)]
56+
57+
for i in range(m):
58+
for j in range(n):
59+
top = prefix_sum[i-1][j] if i > 0 else 0
60+
left = prefix_sum[i][j-1] if j > 0 else 0
61+
topleft = prefix_sum[i-1][j-1] if i > 0 and j > 0 else 0
62+
63+
prefix_sum[i][j] = matrix[i][j] + top + left - topleft
64+
65+
return prefix_sum
66+
```
67+
68+
### Complete Implementation with Query Function
69+
```python
70+
class PrefixSum2D:
71+
def __init__(self, matrix):
72+
self.matrix = matrix
73+
self.m, self.n = len(matrix), len(matrix[0]) if matrix else (0, 0)
74+
self.prefix = self._compute_prefix()
75+
76+
def _compute_prefix(self):
77+
if not self.matrix or not self.matrix[0]:
78+
return []
79+
80+
prefix = [[0] * self.n for _ in range(self.m)]
81+
82+
for i in range(self.m):
83+
for j in range(self.n):
84+
top = prefix[i-1][j] if i > 0 else 0
85+
left = prefix[i][j-1] if j > 0 else 0
86+
topleft = prefix[i-1][j-1] if i > 0 and j > 0 else 0
87+
88+
prefix[i][j] = self.matrix[i][j] + top + left - topleft
89+
90+
return prefix
91+
92+
def query(self, r1, c1, r2, c2):
93+
"""Query sum from (r1, c1) to (r2, c2) inclusive"""
94+
if r1 < 0 or r1 >= self.m or c1 < 0 or c1 >= self.n:
95+
return 0
96+
if r2 < 0 or r2 >= self.m or c2 < 0 or c2 >= self.n:
97+
return 0
98+
99+
total = self.prefix[r2][c2]
100+
if r1 > 0:
101+
total -= self.prefix[r1 - 1][c2]
102+
if c1 > 0:
103+
total -= self.prefix[r2][c1 - 1]
104+
if r1 > 0 and c1 > 0:
105+
total += self.prefix[r1 - 1][c1 - 1]
106+
return total
107+
```
108+
109+
### Example Usage
110+
```python
111+
matrix = [
112+
[1, 2, 3],
113+
[4, 5, 6],
114+
[7, 8, 9]
115+
]
116+
117+
# Using functional approach
118+
prefix = compute_2d_prefix_sum(matrix)
119+
for row in prefix:
120+
print(row)
121+
# Output:
122+
# [1, 3, 6]
123+
# [5, 12, 21]
124+
# [12, 27, 45]
125+
126+
# Query sum from (0,0) to (1,1)
127+
def query_sum(prefix, r1, c1, r2, c2):
128+
total = prefix[r2][c2]
129+
if r1 > 0:
130+
total -= prefix[r1 - 1][c2]
131+
if c1 > 0:
132+
total -= prefix[r2][c1 - 1]
133+
if r1 > 0 and c1 > 0:
134+
total += prefix[r1 - 1][c1 - 1]
135+
return total
136+
137+
result = query_sum(prefix, 0, 0, 1, 1)
138+
print(f"Sum from (0,0) to (1,1): {result}") # Expected: 12 (1+2+4+5)
139+
140+
# Using class approach
141+
prefix_obj = PrefixSum2D(matrix)
142+
result = prefix_obj.query(1, 1, 2, 2)
143+
print(f"Sum from (1,1) to (2,2): {result}") # Expected: 5+6+8+9 = 28
144+
```
145+
146+
### Edge Cases and Validation
147+
```python
148+
# Empty matrix
149+
empty_matrix = []
150+
prefix_empty = compute_2d_prefix_sum(empty_matrix)
151+
print(prefix_empty) # Expected: []
152+
153+
# Single cell matrix
154+
single_cell = [[5]]
155+
prefix_single = compute_2d_prefix_sum(single_cell)
156+
print(prefix_single) # Expected: [[5]]
157+
158+
# Single row matrix
159+
single_row = [[1, 2, 3, 4]]
160+
prefix_row = compute_2d_prefix_sum(single_row)
161+
print(prefix_row) # Expected: [[1, 3, 6, 10]]
162+
163+
# Single column matrix
164+
single_col = [[1], [2], [3]]
165+
prefix_col = compute_2d_prefix_sum(single_col)
166+
print(prefix_col)
167+
# Expected:
168+
# [[1],
169+
# [3],
170+
# [6]]
171+
172+
# Query entire matrix
173+
total_sum = query_sum(prefix, 0, 0, 2, 2)
174+
print(f"Total matrix sum: {total_sum}") # Expected: 45 (1+2+3+4+5+6+7+8+9)
175+
```
176+
```

0 commit comments

Comments
 (0)