The problem. You're given an m × n integer matrix where each row is sorted, and each row starts with a value bigger than the last value of the row before. Given a target, return true if it's in the matrix. Your solution must run in O(log(m · n)) time.
matrix = [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 60]], target = 3 -> true
matrix = [[1, 3, 5, 7], [10, 11, 16, 20], [23, 30, 34, 60]], target = 13 -> falseSorted matrices come in two kinds, and each has its own trick. When rows continue one another, as here, the whole matrix is secretly one sorted list: binary search it with index arithmetic. When rows and columns are only sorted separately (next lesson), start in a corner where one comparison rules out a whole row or column.
function searchMatrix(matrix, target) { for (const row of matrix) { for (const value of row) if (value === target) return true; } return false;}Time O(m · n), space O(1).
First binary search the rows for the last row whose first value is at most the target — the only row that could hold it. Then binary search inside that row.
function searchMatrix(matrix, target) { let low = 0, high = matrix.length - 1; while (low < high) { // the last row starting at or below target const mid = low + Math.ceil((high - low) / 2); // round up: low = mid must make progress if (matrix[mid][0] <= target) low = mid; else high = mid - 1; } const row = matrix[low]; let l = 0, h = row.length - 1; while (l <= h) { // plain binary search in that row const mid = l + Math.floor((h - l) / 2); if (row[mid] === target) return true; if (row[mid] < target) l = mid + 1; else h = mid - 1; } return false;}Time O(log m + log n) = O(log(m · n)), space O(1). Note the last-yes search for the row: mid rounds up so that low = mid always moves.
Binary search positions 0..m·n−1 and turn each position into a row and column only to read it.
function searchMatrix(matrix, target) { const rows = matrix.length, cols = matrix[0].length; let low = 0, high = rows * cols - 1; while (low <= high) { const mid = Math.floor((low + high) / 2); const r = Math.floor(mid / cols), c = mid % cols; if (matrix[r][c] === target) return true; if (matrix[r][c] < target) low = mid + 1; else high = mid - 1; } return false;}Time O(log(m · n)), space O(1). The matrix is never copied: mid / cols and mid % cols turn a position in the imaginary flat list into a real row and column.
[[1, 3, 5]] and [[1], [3], [5]].[[5]] with target 5 and 6.matrix[0][0] or bigger than the last value.