You are given a m x n
matrix mat
and an integer k
. Your task is to return a matrix answer
where each answer[i][j]
is the sum of all elements mat[r][c]
that satisfy the following conditions:
i - k <= r <= i + k
j - k <= c <= j + k
(r, c)
is a valid position within the matrix.In other words, for each cell in the matrix, you need to calculate the sum of all its neighbors within a range of k
in all directions, considering boundary conditions.
Example 1:
Input: mat = [[1,2,3],[4,5,6],[7,8,9]], k = 1
Output: [[12,21,16],[27,45,33],[24,39,28]]
Explanation: For the cell (1,1) with value 5, the neighbors within k=1 are [1,2,3,4,5,6,7,8,9]. The sum is 45. For the cell (0,0) with value 1, the neighbors within k=1 are [1,2,4,5]. The sum is 12. You need to do this calculation for every cell to create the output matrix.
Example 2:
Input: mat = [[1,2,3],[4,5,6],[7,8,9]], k = 2
Output: [[45,45,45],[45,45,45],[45,45,45]]
In this case, k is large enough that every cell's neighborhood includes the entire matrix. This means every answer[i][j] should be the sum of all elements in the matrix.
Constraints:
m == mat.length
n == mat[i].length
1 <= m, n, k <= 100
1 <= mat[i][j] <= 100
Can you implement a function that efficiently calculates the matrix block sum?
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
For each position in the matrix, we need to find the sum of the numbers in a surrounding block. The brute force approach calculates this sum individually for every single position by directly adding up the numbers within the block.
Here's how the algorithm would work step-by-step:
def matrix_block_sum_brute_force(matrix, k_size):
number_of_rows = len(matrix)
number_of_columns = len(matrix[0])
block_sum_matrix = [[0] * number_of_columns for _ in range(number_of_rows)]
for row_index in range(number_of_rows):
for column_index in range(number_of_columns):
# Need to calculate block sum for current position.
block_sum = 0
for block_row in range(max(0, row_index - k_size), min(number_of_rows, row_index + k_size + 1)):
# We must iterate across the rows in the block around current position
for block_column in range(max(0, column_index - k_size), min(number_of_columns, column_index + k_size + 1)):
# We must also iterate across columns in block.
block_sum += matrix[block_row][block_column]
# Store sum in result matrix.
block_sum_matrix[row_index][column_index] = block_sum
return block_sum_matrix
The trick to solving this problem efficiently is to precompute the sum of every rectangular sub-region of the matrix. Then, for each query, you can quickly calculate the block sum using these precomputed values, instead of recalculating the sum each time. This avoids redundant calculations and significantly speeds things up.
Here's how the algorithm would work step-by-step:
def matrix_block_sum(matrix, radius):
rows = len(matrix)
cols = len(matrix[0])
# cumulative_sum_matrix[i][j] is sum of matrix[0...i-1][0...j-1]
cumulative_sum_matrix = [[0] * (cols + 1) for _ in range(rows + 1)]
for row_index in range(1, rows + 1):
for col_index in range(1, cols + 1):
cumulative_sum_matrix[row_index][col_index] = matrix[row_index - 1][col_index - 1] + \
cumulative_sum_matrix[row_index - 1][col_index] + \
cumulative_sum_matrix[row_index][col_index - 1] - \
cumulative_sum_matrix[row_index - 1][col_index - 1]
result_matrix = [[0] * cols for _ in range(rows)]
for row_index in range(rows):
for col_index in range(cols):
row_start = max(0, row_index - radius)
col_start = max(0, col_index - radius)
row_end = min(rows, row_index + radius + 1)
col_end = min(cols, col_index + radius + 1)
# Applying inclusion-exclusion principle
result_matrix[row_index][col_index] = cumulative_sum_matrix[row_end][col_end] - \
cumulative_sum_matrix[row_start][col_end] - \
cumulative_sum_matrix[row_end][col_start] + \
cumulative_sum_matrix[row_start][col_start]
return result_matrix
Case | How to Handle |
---|---|
Null or empty matrix | Return an empty matrix (or a matrix of the same dimensions filled with zeros) after checking for null or zero dimensions. |
K is zero | The sum at each cell becomes the value of the cell itself, so return a matrix where each cell is equal to the original matrix. |
K is larger than the matrix dimensions | Treat K as the maximum possible index for rows and columns, effectively summing the whole input matrix. |
Matrix contains negative numbers | The prefix sum calculation handles negative numbers correctly, contributing negatively to sums. |
Integer overflow in the prefix sum calculation | Use a data type like `long` to store the prefix sum to prevent integer overflow issues during accumulation and differencing. |
Single element matrix | Return a matrix of the same dimension where the single element is the original element if K >= 0 or 0 if K < 0 in some problem modifications |
Large matrix dimensions impacting memory | The prefix sum matrix can be optimized to in-place modification of the original matrix for reduced memory footprint but impacts the original input. |
K is a very large number | Clamp K to the maximum possible row and column index for efficient processing, treating the range as the entire matrix size. |