Before attempting this problem, you should be comfortable with:
We consider every possible submatrix by fixing all four corners (top-left and bottom-right). For each submatrix, we sum all its elements and check if it equals the target. This is the most straightforward approach but very slow.
(r1, r2) defining vertical bounds.(c1, c2) defining horizontal bounds.res.class Solution:
def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
for r1 in range(ROWS):
for r2 in range(r1, ROWS):
for c1 in range(COLS):
for c2 in range(c1, COLS):
subSum = 0
for r in range(r1, r2 + 1):
for c in range(c1, c2 + 1):
subSum += matrix[r][c]
if subSum == target:
res += 1
return resWhere is the number of rows and is the number of columns of the given matrix.
By precomputing a 2D prefix sum, any submatrix sum can be calculated in O(1) using inclusion-exclusion. We still enumerate all submatrix boundaries, but computing each sum is now constant time instead of proportional to the submatrix size.
subSum[r][c] represents the sum of all elements from (0,0) to (r,c).(r1, c1) and (r2, c2):subSum[r2][c2] - subSum[r1-1][c2] - subSum[r2][c1-1] + subSum[r1-1][c1-1].class Solution:
def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
sub_sum = [[0] * COLS for _ in range(ROWS)]
for r in range(ROWS):
for c in range(COLS):
top = sub_sum[r - 1][c] if r > 0 else 0
left = sub_sum[r][c - 1] if c > 0 else 0
top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0
sub_sum[r][c] = matrix[r][c] + top + left - top_left
res = 0
for r1 in range(ROWS):
for r2 in range(r1, ROWS):
for c1 in range(COLS):
for c2 in range(c1, COLS):
top = sub_sum[r1 - 1][c2] if r1 > 0 else 0
left = sub_sum[r2][c1 - 1] if c1 > 0 else 0
top_left = sub_sum[r1 - 1][c1 - 1] if min(r1, c1) > 0 else 0
cur_sum = sub_sum[r2][c2] - top - left + top_left
if cur_sum == target:
res += 1
return resWhere is the number of rows and is the number of columns of the given matrix.
We reduce the 2D problem to multiple 1D subarray sum problems. After fixing a row range (r1 to r2), the submatrix sum becomes a horizontal prefix sum across columns. We apply the classic technique of using a hash map to count how many previous prefix sums differ by exactly the target.
(r1, r2):{0: 1} to handle subarrays starting from column 0.curSum - target from the map to res.class Solution:
def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
sub_sum = [[0] * COLS for _ in range(ROWS)]
for r in range(ROWS):
for c in range(COLS):
top = sub_sum[r - 1][c] if r > 0 else 0
left = sub_sum[r][c - 1] if c > 0 else 0
top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0
sub_sum[r][c] = matrix[r][c] + top + left - top_left
res = 0
for r1 in range(ROWS):
for r2 in range(r1, ROWS):
count = defaultdict(int)
count[0] = 1
for c in range(COLS):
cur_sum = sub_sum[r2][c] - (sub_sum[r1 - 1][c] if r1 > 0 else 0)
res += count[cur_sum - target]
count[cur_sum] += 1
return resWhere is the number of rows and is the number of columns of the given matrix.
Similar to the horizontal approach, but we fix column bounds instead of row bounds. For each pair of columns (c1 to c2), we maintain a running row sum and apply the hash map technique vertically. This can be more efficient when there are fewer columns than rows.
(c1, c2):rowPrefix[r] stores the sum of elements in row r from column c1 to c2.class Solution:
def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int:
ROWS, COLS = len(matrix), len(matrix[0])
res = 0
for c1 in range(COLS):
row_prefix = [0] * ROWS
for c2 in range(c1, COLS):
for r in range(ROWS):
row_prefix[r] += matrix[r][c2]
count = defaultdict(int)
count[0] = 1
cur_sum = 0
for r in range(ROWS):
cur_sum += row_prefix[r]
res += count[cur_sum - target]
count[cur_sum] += 1
return resWhere is the number of rows and is the number of columns of the given matrix.
The inclusion-exclusion principle for 2D prefix sums is error-prone. The correct formula is subSum[r2][c2] - subSum[r1-1][c2] - subSum[r2][c1-1] + subSum[r1-1][c1-1]. Forgetting to add back the top-left corner (which gets subtracted twice) leads to incorrect results.
When computing prefix sums or querying submatrix sums, accessing indices like r1-1 or c1-1 when r1=0 or c1=0 causes out-of-bounds errors. You must handle these boundary cases explicitly by checking if the index is valid before accessing.
In the 1D subarray sum reduction, the hash map must be initialized with {0: 1} to count subarrays starting from the beginning of the row range. Without this initialization, you miss all submatrices whose sum equals exactly the target from the leftmost column.
The optimal approach iterates over the smaller dimension for the outer loops. If you iterate over rows when there are many more rows than columns, the time complexity becomes worse than necessary. Always consider iterating over min(m, n) for the pair loops.
When the matrix contains large values (positive or negative), prefix sums can overflow 32-bit integers. Use 64-bit integers or appropriate data types to handle cumulative sums, especially when the matrix is large.