Implement the class SubrectangleQueries
which receives a rows x cols
rectangle as a matrix of integers in the constructor and supports two methods:
1. updateSubrectangle(int row1, int col1, int row2, int col2, int newValue)
newValue
in the subrectangle whose upper left coordinate is (row1,col1)
and bottom right coordinate is (row2,col2)
.2. getValue(int row, int col)
(row,col)
from the rectangle.
Example 1:
Input ["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue","getValue"] [[[[1,2,1],[4,3,4],[3,2,1],[1,1,1]]],[0,2],[0,0,3,2,5],[0,2],[3,1],[3,0,3,2,10],[3,1],[0,2]] Output [null,1,null,5,5,null,10,5] Explanation SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,2,1],[4,3,4],[3,2,1],[1,1,1]]); // The initial rectangle (4x3) looks like: // 1 2 1 // 4 3 4 // 3 2 1 // 1 1 1 subrectangleQueries.getValue(0, 2); // return 1 subrectangleQueries.updateSubrectangle(0, 0, 3, 2, 5); // After this update the rectangle looks like: // 5 5 5 // 5 5 5 // 5 5 5 // 5 5 5 subrectangleQueries.getValue(0, 2); // return 5 subrectangleQueries.getValue(3, 1); // return 5 subrectangleQueries.updateSubrectangle(3, 0, 3, 2, 10); // After this update the rectangle looks like: // 5 5 5 // 5 5 5 // 5 5 5 // 10 10 10 subrectangleQueries.getValue(3, 1); // return 10 subrectangleQueries.getValue(0, 2); // return 5
Example 2:
Input ["SubrectangleQueries","getValue","updateSubrectangle","getValue","getValue","updateSubrectangle","getValue"] [[[[1,1,1],[2,2,2],[3,3,3]]],[0,0],[0,0,2,2,100],[0,0],[2,2],[1,1,2,2,20],[2,2]] Output [null,1,null,100,100,null,20] Explanation SubrectangleQueries subrectangleQueries = new SubrectangleQueries([[1,1,1],[2,2,2],[3,3,3]]); subrectangleQueries.getValue(0, 0); // return 1 subrectangleQueries.updateSubrectangle(0, 0, 2, 2, 100); subrectangleQueries.getValue(0, 0); // return 100 subrectangleQueries.getValue(2, 2); // return 100 subrectangleQueries.updateSubrectangle(1, 1, 2, 2, 20); subrectangleQueries.getValue(2, 2); // return 20
Constraints:
500
operations considering both methods: updateSubrectangle
and getValue
.1 <= rows, cols <= 100
rows == rectangle.length
cols == rectangle[i].length
0 <= row1 <= row2 < rows
0 <= col1 <= col2 < cols
1 <= newValue, rectangle[i][j] <= 10^9
0 <= row < rows
0 <= col < cols
This problem involves designing a data structure to efficiently handle subrectangle updates and queries on a given rectangle. The solution uses a list to store the update operations. When a getValue
query is made, it iterates through the update operations in reverse chronological order (from most recent to oldest). If a subrectangle update covers the queried coordinate, the updated value is returned; otherwise, the original value from the initial rectangle is used. This approach avoids the need to modify the underlying rectangle matrix directly for every update, leading to significant performance improvements for a large number of updates.
Time Complexity:
__init__
(Constructor): O(1). The constructor simply initializes the rectangle and the list to store operations. It doesn't perform any iterations proportional to the input size.
updateSubrectangle
: O(1). The operation appends a new tuple/array to the list which takes constant time.
getValue
: O(U), where U is the number of update operations. In the worst case, it needs to iterate through the entire list of update operations.
Space Complexity:
ops
list, which stores the details of each update operation. The original rectangle is O(R*C), where R and C are rows and columns respectively but this is constant.The Python code efficiently implements the described approach.
class SubrectangleQueries:
def __init__(self, rectangle: List[List[int]]):
self.g = rectangle # Store the initial rectangle
self.ops = [] # Initialize an empty list to store update operations
def updateSubrectangle(
self, row1: int, col1: int, row2: int, col2: int, newValue: int
) -> None:
self.ops.append((row1, col1, row2, col2, newValue)) #Append update operation details
def getValue(self, row: int, col: int) -> int:
for r1, c1, r2, c2, v in self.ops[::-1]: #Iterate in reverse order of operations
if r1 <= row <= r2 and c1 <= col <= c2: # Check if the coordinate is within the updated subrectangle
return v #Return the updated value
return self.g[row][col] # Otherwise return the original value
The other language implementations follow the same logic, with minor syntactic differences. The key is the use of a list to record update operations and the reverse iteration to find the most recent relevant update. This approach provides an efficient solution compared to repeatedly updating the entire rectangle.