Searching a sorted matrix
In one line
If the whole matrix reads as one sorted list row by row, binary search it as a flat array in O(log(m x n)); if only rows and columns are each sorted, walk a staircase from a corner in O(m + n).
What it is
Interviewers use two different kinds of sorted matrix, and they need different algorithms. In a fully sorted matrix, each row is sorted and each row starts after the previous row ends, so reading row by row gives one sorted list. You can treat it as a flat array of m x n elements and map index i to row i // n and column i % n.
In a row-and-column sorted matrix, every row is sorted left to right and every column top to bottom, but a row can start below where the previous one ended. Here you start at the top-right corner: if the value is too big, move left (the whole column below is bigger); if it is too small, move down (the whole row to the left is smaller). Each step removes a row or a column.
Why interviewers ask
The question tests whether you read the constraints carefully and pick the right technique, then translate between 1D and 2D indexes without off-by-one errors. A strong answer names both matrix types, their complexities, and explains why the staircase starts at the top-right or bottom-left corner but not the top-left.
How it works
- 1Fully sorted matrix: set lo = 0 and hi = m x n - 1 and run classic binary search.
- 2For each mid, read matrix[mid // n][mid % n], where n is the number of columns. Compare and move lo or hi exactly as in a 1D array.
- 3Row-and-column sorted matrix: start at row 0, column n - 1 (top-right). From there, going left decreases values and going down increases them, so every comparison has one clear direction.
- 4If the value equals the target, done. If it is greater, the target cannot be in this column (everything below is even greater): move left. If it is smaller, the target cannot be in this row (everything to the left is even smaller): move down.
- 5Stop when you leave the matrix: the target is not present. You take at most m + n steps.
- 6For 'kth smallest' in a row-and-column sorted matrix, binary search on the value range and use the staircase walk to count entries <= mid.
Worked example · Two matrices, two methods
- Fully sorted [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 60]], target 3. m = 3, n = 4, lo = 0, hi = 11.
- mid = 5 maps to (1, 1) = 11 > 3, so hi = 4. mid = 2 maps to (0, 2) = 5 > 3, so hi = 1. mid = 0 maps to (0, 0) = 1 < 3, so lo = 1. mid = 1 maps to (0, 1) = 3: found in 4 comparisons.
- Row-and-column sorted [[1, 4, 7, 11], [2, 5, 8, 12], [3, 6, 9, 16], [10, 13, 14, 17]], target 5. Start at (0, 3) = 11 > 5: move left.
- (0, 2) = 7 > 5: move left. (0, 1) = 4 < 5: move down. (1, 1) = 5: found after 4 steps.
- Notice that this second matrix is not fully sorted: row 1 starts with 2, which is smaller than 11 at the end of row 0, so flattening it would not give a sorted list.
Picture it
A fully sorted matrix is a book: pages in order, lines in order, so you can open it in the middle. A row-and-column sorted matrix is like a hill seen from a corner: from the top-right, stepping left always goes downhill and stepping down always goes uphill, so you always know which way to step.
Reference code
def search_flat_matrix(matrix, target):
"""Rows sorted and each row starts after the previous row ends."""
if not matrix or not matrix[0]:
return False
rows, cols = len(matrix), len(matrix[0])
lo, hi = 0, rows * cols - 1 # treat the matrix as one sorted array
while lo <= hi:
mid = (lo + hi) // 2
value = matrix[mid // cols][mid % cols]
if value == target:
return True
if value < target:
lo = mid + 1
else:
hi = mid - 1
return False
def search_staircase(matrix, target):
"""Every row and every column sorted ascending. O(rows + cols)."""
if not matrix or not matrix[0]:
return False
r, c = 0, len(matrix[0]) - 1 # start at the top-right corner
while r < len(matrix) and c >= 0:
if matrix[r][c] == target:
return True
if matrix[r][c] > target:
c -= 1 # whole column below is even bigger
else:
r += 1 # whole row to the left is even smaller
return False
search_flat_matrix is classic binary search over virtual indexes 0 to m x n - 1, using // and % to convert to row and column: O(log(m x n)) time. search_staircase removes one row or one column per step: O(m + n) time. Both use O(1) extra space.
Key patterns
Flatten a fully sorted matrix
When: Rows sorted and each row starts after the previous ends
How: Binary search i in [0, m x n - 1] with matrix[i // n][i % n]. O(log(m x n)).
Staircase walk
When: Rows and columns each sorted, rows overlap
How: Start top-right (or bottom-left); move left if too big, down if too small. O(m + n).
Row then column
When: Fully sorted matrix, prefer two simple searches
How: Binary search the first column for the last row whose first value is <= target, then binary search that row. Same O(log m + log n).
Kth smallest by value
When: Kth smallest element in a row-and-column sorted matrix
How: Binary search values between matrix[0][0] and matrix[m-1][n-1]; count entries <= mid with a staircase walk; first value whose count >= k.
Real-world use
Paged sorted storage
Database B-tree leaves and LSM SSTables split one sorted key list into fixed-size pages, which is effectively a fully sorted matrix: the engine binary searches the page index, then binary searches inside the chosen page.
Engineering lookup tables
Engine control units and simulation code store 2D tables, such as fuel amount by RPM and load, with sorted axes; they binary search each axis to find the surrounding cell and interpolate.
Spreadsheet approximate lookups
Excel's XLOOKUP has binary search modes and VLOOKUP with approximate match assumes a sorted first column, so lookups over large sorted tables stay fast.
In a project
A ride-pricing service stores a surge-multiplier table indexed by demand level (rows) and time of day (columns). Both axes are sorted, and each row and column increases. Ops wants to find which cells hit a specific multiplier cap for an audit.
- Confirm the shape: rows and columns are each increasing, but rows overlap, so the matrix is row-and-column sorted, not fully sorted.
- Use the staircase walk from the top-right to check whether a cap value exists, in O(rows + cols).
- To count cells at or below a cap, run the staircase count; to find the k-th smallest multiplier, binary search the value and count with the same walk.
- Add tests with matrices of one row, one column and a target outside the value range.
Impact: On a 2,000 x 2,000 table each audit query touches at most 4,000 cells instead of 4 million, so audits that took seconds per query now run in about a millisecond and can be part of the deploy check.
Trade-offs
Use it when
- Flatten: the matrix is fully sorted row by row
- Staircase: each row and each column is sorted, but rows overlap
- You need many lookups and cannot afford O(m x n) scans
Avoid it when
- Flatten on a matrix that is only row-and-column sorted: it gives wrong answers
- Rows are sorted but columns are not: binary search each row, O(m log n)
- You need many exact lookups on unsorted data: build a hash set once instead
Cost: Fully sorted: O(log(m x n)) = O(log m + log n). Row-and-column sorted: O(m + n). Both O(1) space.
Common mistakes
- Using the flat binary search on a matrix that is only row-and-column sorted.
- Mapping index to row and column with the wrong dimension: it is i // cols and i % cols, not rows.
- Starting the staircase at the top-left or bottom-right, where both moves change the value in the same direction, so there is no decision to make.
- Claiming the staircase is O(log n) or O(m x n); it is O(m + n).
- Forgetting empty matrices or empty rows before reading matrix[0].
Interview questions
Quick revision
- Fully sorted matrix: flatten, index i -> (i // n, i % n), O(log(m x n)).
- Row-and-column sorted: staircase from top-right, O(m + n).
- Staircase: too big -> move left; too small -> move down.
- Top-left and bottom-right corners do not work for the staircase.
- Only rows sorted: binary search each row, O(m log n).
- Kth smallest: binary search on value + staircase count.
- Check for empty matrix and empty rows first.
Check yourself
1. In a fully sorted matrix with 3 rows and 4 columns, which cell does flat index 7 refer to?
2. What is the time complexity of the staircase search on an m x n row-and-column sorted matrix?
3. During the staircase search from the top-right, the current value is greater than the target. What do you do?
4. Rows of [[1, 4], [2, 5]] are sorted and columns are sorted. Can you binary search it as a flat array [1, 4, 2, 5]?
Saved on this device. Create a free account to keep it on every device.
Practise this with Sam
A real mock interview, out loud, with an honest scorecard. Free to start.