Search a 2D Matrix
Problem statement
You get an m x n integer matrix with two properties:
- every row is sorted in ascending order, and
- the first value of each row is greater than the last value of the row above it.
Given a target, return true if it appears anywhere in the matrix and false otherwise. Aim for O(log(m * n)) time.
Examples
Example 1
Input: matrix = [[2, 4, 7], [10, 13, 15], [18, 22, 30]], target = 13
Output: true
Explanation: 13 is in the middle row.
Example 2
Input: matrix = [[2, 4, 7], [10, 13, 15], [18, 22, 30]], target = 16
Output: false
Explanation: 16 would fall between 15 and 18, which are neighbours in reading order.
Hints
Approach
Treat the matrix as one sorted array of length m * n and binary-search it without copying anything.
- Set
lo = 0andhi = m * n - 1. - While
lo <= hi:mid = lo + (hi - lo) // 2;- read the value at row
mid // n, columnmid % n; - compare it to the target and move
loorhiexactly as in ordinary binary search.
- Return
falseif the range empties.
The index conversion is the whole trick. It takes O(log(m·n)) comparisons.
O(log(m·n))Space O(1)class Solution: def searchMatrix(self, matrix: list[list[int]], target: int) -> bool: m, n = len(matrix), len(matrix[0]) lo, hi = 0, m * n - 1 while lo <= hi: mid = lo + (hi - lo) // 2 v = matrix[mid // n][mid % n] if v == target: return True if v < target: lo = mid + 1 else: hi = mid - 1 return FalseFollow-up questions
- Now rows and columns are each sorted, but a row's first value may be smaller than the previous row's last value. Which approach still works?
Frequently asked questions
n is the number of columns, which is how many flat positions each row holds. Position k has k // n full rows before it and sits k % n cells into its own row. Using m breaks as soon as the matrix is not square.
Data split into fixed-size pages or shards behaves like this matrix: log files rotated at a fixed number of lines, or metrics stored in fixed-size blocks. Converting a global offset to (block, offset-within-block) with // and % is the same step.
That also runs in O(log m + log n), which equals O(log(m·n)). It is a valid answer; the flat-index version is shorter and has fewer boundary cases.