Search a 2D Matrix
Flatten then binary search
Treat the 2D matrix as a flattened sorted array. Index arithmetic.
Problem
You are given an m x n matrix with two guarantees:
- each row is sorted in ascending order;
- the first integer of each row is greater than the last integer of the previous row.
Return true if target exists in the matrix, otherwise false.
Intuition
The matrix is not "2D" in any algorithmically interesting sense. Because every row starts after the previous row ends, the entire matrix is already sorted if you read it left to right, top to bottom.
That means you do not need a special matrix algorithm. You need a one-dimensional binary search plus a coordinate mapping:
mid / colsgives the row;mid % colsgives the column.
The only extra work is handling the empty-matrix case cleanly.
Approach
Flattened Index Search
O(log(mn))O(1)Treat the matrix as if it were one sorted array of length m * n. Binary
search that virtual array, and map each midpoint back to (row, col).
The key invariant is unchanged from #704: if target exists, it is always
inside the current half-open interval.
impl Solution {
pub fn search_matrix(matrix: Vec<Vec<i32>>, target: i32) -> bool {
if matrix.is_empty() || matrix[0].is_empty() {
return false;
}
let cols = matrix[0].len();
let mut lo = 0usize;
let mut hi = matrix.len() * cols;
while lo < hi {
let mid= lo + (hi - lo) / 2;
let value= matrix[mid / cols][mid % cols];
if value < target {
lo= mid + 1;
} else if value > target {
hi = mid;
} else {
return true;
}
}
false
}
}
function searchMatrix(matrix: number[][], target: number): boolean {
if (matrix.length === 0 || matrix[0].length === 0) return false;
const rows = matrix.length;
const cols = matrix[0].length;
let lo = 0;
let hi = rows * cols;
while (lo < hi) {
const mid = lo + Math.floor((hi - lo) / 2);
const value = matrix[Math.floor(mid / cols)][mid % cols];
if (value < target) {
lo = mid + 1;
} else if (value > target) {
hi = mid;
} else {
return true;
}
}
return false;
}Trace
Search target = 13 in matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]]:
| lo | hi | mid | value | coords | action |
|---|---|---|---|---|---|
| 0 | 12 | 6 | 16 | (1, 2) | move hi to 6 |
| 0 | 6 | 3 | 7 | (0, 3) | move lo to 4 |
| 4 | 6 | 5 | 11 | (1, 1) | move lo to 6 |
The interval collapses with no equality hit, so the answer is false.
Edge cases
- Empty matrix — return
falsebefore indexing row 0. - Single row — the algorithm degenerates to ordinary binary search.
- Single column — the same mapping still works because
mid % colsis always0.
Takeaway
Whenever a 2D structure has a global sorted order, flatten it before you overthink it. The real skill is recognizing when the data structure is a presentation detail, not an algorithmic constraint.
Get the template perfect: lo, hi, mid, and the loop condition. Practice until it’s automatic.
Lower bound. Understand why lo ends up at the insertion point.
Binary search on a property, not a value. Which half is sorted?
Binary search on the ANSWER. This is the gateway to a whole class of hards.
More in Binary Search Mastery
Get the template perfect: lo, hi, mid, and the loop condition. Practice until it’s automatic.
Lower bound. Understand why lo ends up at the insertion point.
Binary search on a property, not a value. Which half is sorted?
Binary search on the ANSWER. This is the gateway to a whole class of hards.