Given a 2D matrix matrix
, handle multiple queries of the following type:
matrix
.matrix
inside the rectangle defined by its upper left corner (row1, col1)
and lower right corner (row2, col2)
.Implement the NumMatrix
class:
NumMatrix(int[][] matrix)
Initializes the object with the 2D integer matrix matrix
.void update(int row, int col, int val)
Updates the value of matrix[row][col]
to be val
.int sumRegion(int row1, int col1, int row2, int col2)
Returns the sum of the elements of matrix
inside the rectangle defined by its upper left corner (row1, col1)
and lower right corner (row2, col2)
.You must design an algorithm where update
and sumRegion
are both O(log(n))
time complexity.
Example 1:
Input ["NumMatrix", "sumRegion", "update", "sumRegion"] [[[[3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5]]], [2, 1, 4, 3], [3, 2, 2], [2, 1, 4, 3]] Output [null, 8, null, 10] Explanation NumMatrix numMatrix = new NumMatrix([[3, 0, 1, 4, 2], [5, 6, 3, 2, 1], [1, 2, 0, 1, 5], [4, 1, 0, 1, 7], [1, 0, 3, 0, 5]]); numMatrix.sumRegion(2, 1, 4, 3); // return 8 numMatrix.update(3, 2, 2); numMatrix.sumRegion(2, 1, 4, 3); // return 10
Constraints:
m == matrix.length
n == matrix[i].length
1 <= m, n <= 200
-105 <= matrix[i][j] <= 105
0 <= row < m
0 <= col < n
-105 <= val <= 105
0 <= row1 <= row2 < m
0 <= col1 <= col2 < n
500
calls will be made to update
and sumRegion
.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 method calculates range sums by directly recomputing the sum within the specified region every time it's needed. When the matrix changes, we simply update the matrix with the new value and move on. Basically, it's doing the most obvious and straightforward calculation each time.
Here's how the algorithm would work step-by-step:
class NumMatrix:
def __init__(self, matrix):
self.matrix = matrix
def update(self, row, col, value):
# Updates the value in the matrix at the specified position
self.matrix[row][col] = value
def sumRegion(self, row1, col1, row2, col2):
total_sum = 0
# Iterate through the rows within the specified range
for row_index in range(row1, row2 + 1):
# Iterate through the columns within the specified range
for col_index in range(col1, col2 + 1):
total_sum += self.matrix[row_index][col_index]
return total_sum
The key to efficiently solving this problem lies in pre-calculating and storing sums of rectangular regions of the matrix. This allows us to quickly retrieve range sums and update values without recalculating the whole matrix repeatedly. We use a structure that is similar to the original matrix, but helps with these two operations.
Here's how the algorithm would work step-by-step:
class NumMatrix:
def __init__(self, matrix):
self.matrix = matrix
if not matrix or not matrix[0]:
self.sum_matrix = []
return
rows = len(matrix)
cols = len(matrix[0])
self.sum_matrix = [[0] * (cols + 1) for _ in range(rows + 1)]
# Precalculate the sum of all values from the top left.
for row_index in range(1, rows + 1):
for col_index in range(1, cols + 1):
self.sum_matrix[row_index][col_index] = self.sum_matrix[row_index - 1][col_index] + self.sum_matrix[row_index][col_index - 1] - self.sum_matrix[row_index - 1][col_index - 1] + matrix[row_index - 1][col_index - 1]
def update(self, row, col, value):
# Updates the original matrix with the new value.
self.matrix[row][col] = value
rows = len(self.matrix)
cols = len(self.matrix[0])
self.sum_matrix = [[0] * (cols + 1) for _ in range(rows + 1)]
# Recalculate the sum matrix after the update.
for row_index in range(1, rows + 1):
for col_index in range(1, cols + 1):
self.sum_matrix[row_index][col_index] = self.sum_matrix[row_index - 1][col_index] + self.sum_matrix[row_index][col_index - 1] - self.sum_matrix[row_index - 1][col_index - 1] + self.matrix[row_index - 1][col_index - 1]
def sumRegion(self, row1, col1, row2, col2):
# Use precalculated sums to determine the region sum.
return self.sum_matrix[row2 + 1][col2 + 1] - self.sum_matrix[row1][col2 + 1] - self.sum_matrix[row2 + 1][col1] + self.sum_matrix[row1][col1]
Case | How to Handle |
---|---|
Null or empty matrix | Return immediately from constructor or other methods if matrix is null or has zero rows or columns, to prevent NullPointerExceptions. |
Update indices out of matrix bounds | Throw an IllegalArgumentException or ignore the update if row or col index is out of bounds. |
Sum range indices out of matrix bounds | Throw an IllegalArgumentException or adjust indices to the valid range if row1, col1, row2, or col2 is out of bounds. |
row1 > row2 or col1 > col2 in sumRegion | Swap row1 and row2 or col1 and col2 to ensure that row1 <= row2 and col1 <= col2 before computing the sum. |
Integer overflow in sumRegion calculation | Use long to store the intermediate sum during the sumRegion calculation to avoid integer overflow. |
Very large matrix dimensions (close to integer limits) | Ensure the data structure and algorithm used scales efficiently to handle matrices with dimensions close to integer limits, potentially impacting memory usage or runtime complexity. |
Matrix with very large or very small numbers (close to integer limits) | Consider using long or double if the matrix elements can be very large or very small, to avoid overflow or precision issues during updates or sum calculations. |
Numerous update operations followed by a single sumRegion operation | Consider optimizing the update operation to be efficient as excessive updates with infrequent queries could degrade overall performance depending on the selected algorithm |