Search a 2D Matrix Solution
Given an m × n matrix with sorted rows and each row's first element greater than the previous row's last, determine if a target exists.
Problem Statement
Write an efficient algorithm that searches for a value target in an m × n integer matrix. Each row is sorted left-to-right, and each row's first integer is greater than the previous row's last integer.
Brute Force — O(m · n)
Scan every element. A better approach: binary search the rows to find the right row, then binary search within it — O(log m + log n). But the cleanest optimal solution treats the entire matrix as a single sorted array.
Flattened Binary Search — O(log(m·n))
Treat the 2D matrix as a virtual 1D sorted array. Index k maps to matrix[k / n][k % n]. Run standard binary search on indices 0 to m·n − 1.
row = mid / cols, col = mid % cols. Binary search works on this virtual flat array.
- Step 1:
left = 0,right = m*n - 1. - Step 2: Compute
mid. Map:row = mid / n,col = mid % n. - Step 3: Compare
matrix[row][col]to target. Standard binary search logic.
- First binary search rows to find which row the target belongs to (compare target to row's first and last element).
- Then binary search within that row. Same O(log m + log n) = O(log(m·n)) complexity, but slightly more code.
Visual Walkthrough
Trace: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3:
Code — Java & Python
Complexity Analysis
| Approach | Time | Space | Trade-off |
|---|---|---|---|
| Brute Force | O(m · n) | O(1) | Scans every element |
| Staircase (top-right) | O(m + n) | O(1) | Works for LC 240 too but slower |
| Flattened Binary Search ← optimal | O(log(m·n)) | O(1) | Virtual 1D array via index math |
Edge Cases & Pitfalls
| Case | Input | Why It Matters |
|---|---|---|
| 1×1 matrix | [[5]], target=5 | Single element → mid=0 → found. |
| Single row | [[1,3,5]] | Degenerates to standard 1D binary search. |
| Single column | [[1],[3],[5]] | n=1; mid/1=row, mid%1=0. Works correctly. |
| Not found | target=4 | Falls between 3 and 5 → L crosses R → false. |
mid / m instead of mid / n for the row. The number of columns (n) determines how many indices fit per row. row = mid / n, col = mid % n. Swapping m and n gives wrong coordinates.