Problem
You have a matrix where every row is sorted left to right and every column is sorted top to bottom, but the last element of a row is NOT necessarily smaller than the first element of the next row. Given a target value, return true if it exists anywhere in the matrix.
1 4 7 11 15
2 5 8 12 19
3 6 9 16 22
10 13 14 17 24
18 21 23 26 30
- Input: matrix above, target = 5
- Output: true
- Explanation: 5 is found at row 1, column 1.
A counter-example: target = 20 returns false โ 20 would fall between 19 and 21 in any column scan, but no cell holds exactly 20.
Intuition
The top-right corner is a pivot: it's the largest value in its row and the smallest in its column. If the target is smaller, the entire column can be ruled out (move left). If the target is larger, the entire row can be ruled out (move down). Each comparison eliminates a full row or column, so the search takes at most m + n steps โ far better than checking every cell.
Approach 1 โ Brute Force
Scan every cell in reading order and return true as soon as the target is found.
- Iterate over each row.
- Iterate over each element in the row.
- Return true if the element equals the target.
- Return false after all cells are checked.
1from typing import List
2
3class Solution:
4 def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
5 for row in matrix:
6 for value in row:
7 if value == target:
8 return True
9 return FalseTime: O(mยทn) โ every cell is visited in the worst case. Space: O(1) โ no extra storage.
Approach 2 โ Staircase Search
Start at the top-right corner and use the sorted structure to eliminate a row or column at each step.
- Position
row = 0,col = numCols - 1(top-right corner). - While
rowandcolare in bounds, readcurrent = matrix[row][col]. - If
current == target, return true. - If
current > target, decrementcolโ the entire current column is ruled out. - If
current < target, incrementrowโ the entire current row is ruled out. - Return false if the pointer walks off the matrix.
1from typing import List
2
3class Solution:
4 def searchMatrix(self, matrix: List[List[int]], target: int) -> bool:
5 num_rows, num_cols = len(matrix), len(matrix[0])
6 row, col = 0, num_cols - 1 # top-right corner is the pivot
7
8 while row < num_rows and col >= 0:
9 current = matrix[row][col]
10 if current == target:
11 return True
12 elif current > target:
13 col -= 1 # whole column is too large; eliminate it
14 else:
15 row += 1 # whole row is too small; eliminate it
16
17 return FalseTime: O(m + n) โ each step eliminates a row or a column, so at most m + n steps total. Space: O(1) โ two pointers, no extra allocations.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Brute Force | O(mยทn) | O(1) | Acceptable when the matrix is tiny and code simplicity matters |
| Staircase Search | O(m + n) | O(1) | Always preferred; this is the intended solution |
Common Mistakes
- Applying the Search a 2D Matrix I trick here: The first matrix problem treats the grid as a single sorted array and runs binary search on a virtual index. This matrix breaks that property โ the last element of row 0 can be larger than the first element of row 1 โ so that approach gives wrong answers.
- Starting from the top-left or bottom-right corner: From the top-left, both right and down increase the value, so you cannot eliminate a row or column with a single comparison. The pivot must be a corner where one direction increases and the other decreases โ top-right or bottom-left.
- Reversing the elimination direction: When
current > targetfrom the top-right, you eliminate the column by moving left (col--), not the row (row++). Swapping these causes the pointer to run off the matrix immediately or miss the target. - Wrong while-loop bounds: The loop condition must be
col >= 0, notcol < numCols. After starting atnumCols - 1and only decrementing, the valid range is[0, numCols-1]; the out-of-bounds exit iscol < 0. - Returning false too early for the boundary case: If the target equals the minimum (top-left) or maximum (bottom-right) of the matrix, the staircase still finds it โ but only if the loop runs until
row < numRows && col >= 0, not until either bound is exceeded.
Related Problems
search-a-2d-matrixโ stricter matrix where rows connect globally sorted; binary search on a virtual 1D index applies there but not herekth-smallest-element-in-a-sorted-matrixโ same row-and-column sorted matrix; uses binary search on the value rangefind-peak-elementโ another problem where a smart pointer eliminates half the search space without brute-forcingbinary-searchโ the foundational operation; row-level binary search is a valid O(m log n) middle ground for this problemsearch-in-rotated-sorted-arrayโ similarly exploits structural guarantees to avoid a full scan