Matrix Block Sum
MedPrompt
Given a m x n matrix mat and an integer k, return a matrix answer where each answer[i][j] is the sum of all elements mat[r][c] for:
i - k <= r <= i + k,j - k <= c <= j + k, and(r, c)is a valid position in the matrix.
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]]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]]
Constraints:
m == mat.lengthn == mat[i].length1 <= m, n, k <= 1001 <= mat[i][j] <= 100
Approaches
2 approaches with complexity analysis and trade-offs.
This approach directly translates the problem statement into code. For each cell (i, j) in the output matrix, we iterate over the entire corresponding block in the input matrix, summing up the values. We must carefully handle the matrix boundaries to avoid out-of-bounds errors.
Algorithm
- Initialize an
m x nmatrixanswer. - Iterate through each cell
(i, j)from(0, 0)to(m-1, n-1). - For each
(i, j), initializesum = 0. - Iterate through rows
rfromi - ktoi + k. - Iterate through columns
cfromj - ktoj + k. - If
(r, c)is a valid index inmat, addmat[r][c]tosum. - Set
answer[i][j] = sum. - Return
answer.
Walkthrough
This method involves a straightforward, nested loop structure.
- First, we create an
m x nresult matrixanswer, initialized with zeros. - We then use two outer loops to iterate through each cell
(i, j)of theanswermatrix. - For each
(i, j), we initialize asumvariable to zero. Then, we start another pair of nested loops to iterate through the block defined by the problem. The row indexrwill go fromi - ktoi + k, and the column indexcwill go fromj - ktoj + k. - Inside the innermost loop, we must check if the current cell
(r, c)is within the valid bounds of the original matrixmat(i.e.,0 <= r < mand0 <= c < n). - If
(r, c)is a valid cell, we add its valuemat[r][c]to our runningsum. - After iterating through the entire block, the calculated
sumis placed inanswer[i][j]. - This process is repeated for all cells
(i, j)until theanswermatrix is fully populated.
class Solution { public int[][] matrixBlockSum(int[][] mat, int k) { int m = mat.length; int n = mat[0].length; int[][] answer = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { int sum = 0; // Iterate through the block for (int r = i - k; r <= i + k; r++) { for (int c = j - k; c <= j + k; c++) { // Check if the cell is within the matrix bounds if (r >= 0 && r < m && c >= 0 && c < n) { sum += mat[r][c]; } } } answer[i][j] = sum; } } return answer; }}Complexity
Time
O(m * n * k^2), where `m` and `n` are the dimensions of the matrix. For each of the `m * n` cells, we iterate over a block of size approximately `(2k+1) * (2k+1)`, leading to the complexity.
Space
O(m * n) to store the output matrix `answer`. If the output matrix is not considered extra space, the complexity is O(1).
Trade-offs
Pros
Simple to understand and implement.
Directly follows the problem definition.
Low constant factor in its complexity.
Cons
Highly inefficient due to redundant calculations.
Time complexity is dependent on
k, making it slow for largekvalues.
This optimized approach avoids redundant calculations by pre-computing a sum-area table (also known as an integral image). This table, let's call it dp, stores the sum of all elements in the rectangle from the origin (0, 0) to every other cell (i, j). Once this table is built, the sum of any rectangular block can be calculated in constant time using the values at its four corners.
Algorithm
- Create an integral image matrix
dpof size(m+1) x (n+1). - Populate
dpsuch thatdp[i+1][j+1]contains the sum of the rectangle from(0,0)to(i,j)inmat. - Initialize an
m x nmatrixanswer. - Iterate through each cell
(i, j)from(0, 0)to(m-1, n-1). - For each
(i, j), calculate the block boundaries:r1, c1, r2, c2. - Calculate the block sum using the
dptable:sum = dp[r2+1][c2+1] - dp[r1][c2+1] - dp[r2+1][c1] + dp[r1][c1]. - Set
answer[i][j] = sum. - Return
answer.
Walkthrough
The core idea is to first build an auxiliary matrix dp of size (m+1) x (n+1). dp[i+1][j+1] will store the sum of all elements in the rectangle of mat from (0, 0) to (i, j). The extra row and column in dp act as padding, simplifying the calculation.
Step 1: Build the Integral Image
The dp table is populated using the following recurrence relation:
dp[i+1][j+1] = mat[i][j] + dp[i][j+1] + dp[i+1][j] - dp[i][j]
This step takes O(m * n) time.
Step 2: Calculate Block Sums
After the dp table is ready, we iterate through each cell (i, j) of the original matrix to compute answer[i][j].
For each (i, j), we define the boundaries of the required block, ensuring they are within the matrix dimensions: r1 = max(0, i - k), c1 = max(0, j - k), r2 = min(m - 1, i + k), c2 = min(n - 1, j + k).
The sum of this block can be found in O(1) time using the dp table:
sum = dp[r2+1][c2+1] - dp[r1][c2+1] - dp[r2+1][c1] + dp[r1][c1]
This sum is then assigned to answer[i][j]. This step also takes O(m * n) time.
class Solution { public int[][] matrixBlockSum(int[][] mat, int k) { int m = mat.length; int n = mat[0].length; // Create the integral image (summed-area table) int[][] dp = new int[m + 1][n + 1]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { dp[i + 1][j + 1] = mat[i][j] + dp[i][j + 1] + dp[i + 1][j] - dp[i][j]; } } int[][] answer = new int[m][n]; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { // Determine the block boundaries, clamping to the matrix dimensions int r1 = Math.max(0, i - k); int c1 = Math.max(0, j - k); int r2 = Math.min(m - 1, i + k); int c2 = Math.min(n - 1, j + k); // Use the integral image to calculate the sum in O(1) // Note the +1 offset for dp table indices answer[i][j] = dp[r2 + 1][c2 + 1] - dp[r1][c2 + 1] - dp[r2 + 1][c1] + dp[r1][c1]; } } return answer; }}Complexity
Time
O(m * n). Building the integral image takes O(m * n), and filling the answer matrix also takes O(m * n). The total time is O(m * n) + O(m * n) = O(m * n).
Space
O(m * n) to store the integral image `dp` table and the output `answer` matrix.
Trade-offs
Pros
Highly efficient with a time complexity independent of
k.Avoids redundant computations by pre-calculating prefix sums.
Cons
Requires additional space for the integral image table.
The logic for calculating sums from the integral image can be slightly tricky to get right.
Solutions
Solution
class Solution {private int[][] pre;private int m;private int n;public int[][] matrixBlockSum(int[][] mat, int k) { int m = mat.length, n = mat[0].length; int[][] pre = new int[m + 1][n + 1]; for (int i = 1; i < m + 1; ++i) { for (int j = 1; j < n + 1; ++j) { pre[i][j] = pre[i - 1][j] + pre[i][j - 1] + -pre[i - 1][j - 1] + mat[i - 1][j - 1]; } } this.pre = pre; this.m = m; this.n = n; int[][] ans = new int[m][n]; for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { ans[i][j] = get(i + k + 1, j + k + 1) - get(i + k + 1, j - k) - get(i - k, j + k + 1) + get(i - k, j - k); } } return ans; }private int get(int i, int j) { i = Math.max(Math.min(m, i), 0); j = Math.max(Math.min(n, j), 0); return pre[i][j]; }}class Solution {public: vector<vector<int>> matrixBlockSum(vector<vector<int>> &mat, int k) { int m = mat.size(), n = mat[0].size(); vector<vector<int>> pre(m + 1, vector<int>(n + 1)); for (int i = 1; i < m + 1; ++i) { for (int j = 1; j < n + 1; ++j) { pre[i][j] = pre[i - 1][j] + pre[i][j - 1] + -pre[i - 1][j - 1] + mat[i - 1][j - 1]; } } vector<vector<int>> ans(m, vector<int>(n)); for (int i = 0; i < m; ++i) { for (int j = 0; j < n; ++j) { ans[i][j] = get(i + k + 1, j + k + 1, m, n, pre) - get(i + k + 1, j - k, m, n, pre) - get(i - k, j + k + 1, m, n, pre) + get(i - k, j - k, m, n, pre); } } return ans; } int get(int i, int j, int m, int n, vector<vector<int>> &pre) { i = max(min(m, i), 0); j = max(min(n, j), 0); return pre[i][j]; }};class Solution: def matrixBlockSum(self, mat: List[List[int]], k: int) -> List[List[int]]: m, n = len(mat), len(mat[0]) pre = [[0] * (n + 1) for _ in range(m + 1)] for i in range(1, m + 1): for j in range(1, n + 1): pre[i][j] = (pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + mat[i - 1][j - 1]) def get(i, j): i = max(min(m, i), 0) j = max(min(n, j), 0) return pre[i][j] ans = [[0] * n for _ in range(m)] for i in range(m): for j in range(n): ans[i][j] = (get(i + k + 1, j + k + 1) - get(i + k + 1, j - k) - get(i - k, j + k + 1) + get(i - k, j - k)) return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.