You are given a positive integer n
, indicating that we initially have an n x n
0-indexed integer matrix mat
filled with zeroes.
You are also given a 2D integer array query
. For each query[i] = [row1i, col1i, row2i, col2i]
, you should do the following operation:
1
to every element in the submatrix with the top left corner (row1i, col1i)
and the bottom right corner (row2i, col2i)
. That is, add 1
to mat[x][y]
for all row1i <= x <= row2i
and col1i <= y <= col2i
.Return the matrix mat
after performing every query.
Example 1:
Input: n = 3, queries = [[1,1,2,2],[0,0,1,1]] Output: [[1,1,0],[1,2,1],[0,1,1]] Explanation: The diagram above shows the initial matrix, the matrix after the first query, and the matrix after the second query. - In the first query, we add 1 to every element in the submatrix with the top left corner (1, 1) and bottom right corner (2, 2). - In the second query, we add 1 to every element in the submatrix with the top left corner (0, 0) and bottom right corner (1, 1).
Example 2:
Input: n = 2, queries = [[0,0,1,1]] Output: [[1,1],[1,1]] Explanation: The diagram above shows the initial matrix and the matrix after the first query. - In the first query we add 1 to every element in the matrix.
Constraints:
1 <= n <= 500
1 <= queries.length <= 104
0 <= row1i <= row2i < n
0 <= col1i <= col2i < n
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:
The brute force approach to this problem means going through each instruction one at a time and directly applying it to the grid. We essentially simulate each increment operation without trying to be clever or optimize anything. We update the grid exactly as the instructions tell us to.
Here's how the algorithm would work step-by-step:
def increment_submatrices_by_one(grid, instructions):
number_of_rows = len(grid)
number_of_columns = len(grid[0])
# Iterate through each instruction to update the grid
for instruction in instructions:
top_row, left_column, bottom_row, right_column = instruction
# Iterate through the specified submatrix
for row_index in range(top_row, bottom_row + 1):
# Iterate through the columns of the current row
for column_index in range(left_column, right_column + 1):
# Increment the cell by one
grid[row_index][column_index] += 1
return grid
The efficient approach avoids directly updating all the numbers in each specified area. Instead, it cleverly records how many times each corner of the grid is affected and then calculates the overall effect later.
Here's how the algorithm would work step-by-step:
def increment_submatrices_by_one(grid_rows, grid_cols, updates):
difference_matrix = [[0] * grid_cols for _ in range(grid_rows)]
for top_row, left_col, bottom_row, right_col in updates:
# Mark the top-left corner with +1.
difference_matrix[top_row][left_col] += 1
if bottom_row + 1 < grid_rows:
# Mark the cell below the bottom-right corner with -1.
difference_matrix[bottom_row + 1][left_col] -= 1
if right_col + 1 < grid_cols:
# Mark the cell to the right of the top-right corner with -1.
difference_matrix[top_row][right_col + 1] -= 1
if bottom_row + 1 < grid_rows and right_col + 1 < grid_cols:
difference_matrix[bottom_row + 1][right_col + 1] += 1
# Accumulate values to get the incremented matrix.
result_matrix = [[0] * grid_cols for _ in range(grid_rows)]
for row_index in range(grid_rows):
for col_index in range(grid_cols):
if row_index == 0 and col_index == 0:
result_matrix[row_index][col_index] = difference_matrix[row_index][col_index]
elif row_index == 0:
# Propagate values from the left.
result_matrix[row_index][col_index] = result_matrix[row_index][col_index - 1] + difference_matrix[row_index][col_index]
elif col_index == 0:
# Propagate values from above.
result_matrix[row_index][col_index] = result_matrix[row_index - 1][col_index] + difference_matrix[row_index][col_index]
else:
# Accumulate values from top and left, subtracting the overlap.
result_matrix[row_index][col_index] = result_matrix[row_index - 1][col_index] + result_matrix[row_index][col_index - 1] - result_matrix[row_index - 1][col_index - 1] + difference_matrix[row_index][col_index]
return result_matrix
Case | How to Handle |
---|---|
n is zero or negative | Return an empty matrix or raise an IllegalArgumentException as a matrix with zero or negative dimensions is invalid. |
queries is null or empty | Return a matrix of size n x n filled with zeros, as no updates are needed. |
row1, col1, row2, or col2 are out of bounds (less than 0 or greater than or equal to n) | Handle by either skipping the invalid query, clamping the values to the valid range [0, n-1], or throwing an IllegalArgumentException for invalid input. |
row1 > row2 or col1 > col2 | Treat the submatrix as empty, skipping the increment operation for that particular query. |
n is a very large number (potential memory issues) | Consider using a sparse matrix representation or other memory-efficient data structures if n is extremely large and memory is a constraint. |
Large number of queries | The solution should iterate efficiently over the queries without excessive overhead; consider algorithm optimization for performance. |
Integer overflow if increments are very large or there are many queries on the same submatrix. | Use a larger integer type (e.g., long) to prevent integer overflow during the increment operation or handle overflow errors explicitly. |
All queries represent the entire matrix | The matrix will be incremented by the number of queries across all of its elements and should still produce a valid n x n result. |