Leetcode #308: Range Sum Query 2D - Mutable
In this guide, we solve Leetcode #308 Range Sum Query 2D - Mutable in Python and focus on the core idea that makes the solution efficient.
You will see the intuition, the step-by-step method, and a clean Python implementation you can use in interviews.

Problem Statement
Given a 2D matrix matrix, handle multiple queries of the following types: Update the value of a cell in matrix. Calculate the sum of the elements of matrix inside the rectangle defined by its upper left corner (row1, col1) and lower right corner (row2, col2).
Quick Facts
- Difficulty: Medium
- Premium: Yes
- Tags: Design, Binary Indexed Tree, Segment Tree, Array, Matrix
Intuition
Grid problems are easiest when you define clear row/column boundaries.
A consistent traversal order prevents off-by-one errors.
Approach
Iterate by rows, columns, or layers depending on the requirement.
Keep bounds updated as the traversal progresses.
Steps:
- Define bounds or directions.
- Visit cells in order.
- Update result and move bounds.
Example
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 (i.e. sum of the left red rectangle)
numMatrix.update(3, 2, 2); // matrix changes from left image to right image
numMatrix.sumRegion(2, 1, 4, 3); // return 10 (i.e. sum of the right red rectangle)
Python Solution
class BinaryIndexedTree:
def __init__(self, n):
self.n = n
self.c = [0] * (n + 1)
def lowbit(x):
return x & -x
def update(self, x, delta):
while x <= self.n:
self.c[x] += delta
x += BinaryIndexedTree.lowbit(x)
def query(self, x):
s = 0
while x > 0:
s += self.c[x]
x -= BinaryIndexedTree.lowbit(x)
return s
class NumMatrix:
def __init__(self, matrix: List[List[int]]):
self.trees = []
n = len(matrix[0])
for row in matrix:
tree = BinaryIndexedTree(n)
for j, v in enumerate(row):
tree.update(j + 1, v)
self.trees.append(tree)
def update(self, row: int, col: int, val: int) -> None:
tree = self.trees[row]
prev = tree.query(col + 1) - tree.query(col)
tree.update(col + 1, val - prev)
def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
return sum(
tree.query(col2 + 1) - tree.query(col1)
for tree in self.trees[row1 : row2 + 1]
)
# Your NumMatrix object will be instantiated and called as such:
# obj = NumMatrix(matrix)
# obj.update(row,col,val)
# param_2 = obj.sumRegion(row1,col1,row2,col2)
Complexity
The time complexity is O(m·n). The space complexity is O(1) to O(m·n).
Edge Cases and Pitfalls
Watch for boundary values, empty inputs, and duplicate values where applicable. If the problem involves ordering or constraints, confirm the invariant is preserved at every step.
Summary
This Python solution focuses on the essential structure of the problem and keeps the implementation interview-friendly while meeting the constraints.