A clear explanation of searching a row-sorted and column-sorted matrix using the top-right corner elimination method.
Problem Restatement
We are given an m x n integer matrix and an integer target.
The matrix has two sorted properties:
- Each row is sorted in ascending order from left to right.
- Each column is sorted in ascending order from top to bottom.
We need to return True if target exists in the matrix, and False otherwise.
LeetCode examples include searching for 5, which returns true, and searching for 20, which returns false, in the same sorted matrix. The constraints allow 1 <= m, n <= 300, and values can be between -10^9 and 10^9.
Input and Output
| Item | Meaning |
|---|---|
| Input | Matrix matrix, integer target |
| Output | True if target exists, otherwise False |
| Row property | Each row is sorted left to right |
| Column property | Each column is sorted top to bottom |
Function shape:
class Solution:
def searchMatrix(self, matrix: list[list[int]], target: int) -> bool:
...Examples
Example 1:
Input:
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]
]
target = 5
Output: trueThe value 5 exists at row 1, column 1.
Example 2:
Input:
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]
]
target = 20
Output: falseThe value 20 does not exist in the matrix.
First Thought: Search Every Cell
The simplest method is to check every cell.
class Solution:
def searchMatrix(self, matrix: list[list[int]], target: int) -> bool:
for row in matrix:
for value in row:
if value == target:
return True
return FalseThis is correct, but it ignores the sorted structure.
If the matrix has m rows and n columns, this takes:
O(m * n)We can do better.
Key Insight
Start from the top-right corner.
At position (row, col), let:
value = matrix[row][col]This position is special because:
- Everything to the left is smaller or equal.
- Everything below is larger or equal.
So we can eliminate one row or one column each step.
If value is too large
If:
value > targetthen every value below it in the same column is also too large, because columns are sorted top to bottom.
So the target cannot be in this column.
Move left:
col -= 1If value is too small
If:
value < targetthen every value to the left in the same row is also too small, because rows are sorted left to right.
So the target cannot be in this row.
Move down:
row += 1If value equals target
Return True.
Algorithm
- Start at the top-right corner:
row = 0col = n - 1
- While
row < mandcol >= 0:- If
matrix[row][col] == target, returnTrue. - If
matrix[row][col] > target, move left. - If
matrix[row][col] < target, move down.
- If
- If we leave the matrix, return
False.
Walkthrough
Use 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]
]Search for:
target = 5Start at top-right:
| Position | Value | Comparison | Move |
|---|---|---|---|
(0, 4) | 15 | 15 > 5 | left |
(0, 3) | 11 | 11 > 5 | left |
(0, 2) | 7 | 7 > 5 | left |
(0, 1) | 4 | 4 < 5 | down |
(1, 1) | 5 | found | return True |
Correctness
At every step, the algorithm is positioned at some cell (row, col).
If matrix[row][col] > target, then every value below it in column col is also greater than or equal to matrix[row][col], and therefore greater than target. So column col cannot contain the target in any remaining row. Moving left removes only impossible cells.
If matrix[row][col] < target, then every value to the left in row row is less than or equal to matrix[row][col], and therefore less than target. So row row cannot contain the target in any remaining column. Moving down removes only impossible cells.
If matrix[row][col] == target, the algorithm returns True, which is correct.
Each move eliminates one full row or one full column from the remaining search area. Since the algorithm only removes cells that cannot contain the target, it never discards a valid answer.
If the search exits the matrix, all possible rows or columns have been eliminated, so the target does not exist in the matrix. Returning False is correct.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(m + n) | Each step moves one row down or one column left |
| Space | O(1) | Only two indices are stored |
Here, m is the number of rows, and n is the number of columns.
Implementation
class Solution:
def searchMatrix(self, matrix: list[list[int]], target: int) -> bool:
m = len(matrix)
n = len(matrix[0])
row = 0
col = n - 1
while row < m and col >= 0:
value = matrix[row][col]
if value == target:
return True
if value > target:
col -= 1
else:
row += 1
return FalseCode Explanation
Get the matrix size:
m = len(matrix)
n = len(matrix[0])Start from the top-right corner:
row = 0
col = n - 1Continue while the position is valid:
while row < m and col >= 0:Check the current value:
value = matrix[row][col]If it matches, return immediately:
if value == target:
return TrueIf the value is too large, move left:
if value > target:
col -= 1Otherwise, the value is too small, so move down:
else:
row += 1If the loop ends, the target was not found:
return FalseAlternative: Binary Search Each Row
Because each row is sorted, we can binary search every row.
This gives:
O(m log n)That is valid, but the top-right method is usually better because it uses both row and column sorting.
Testing
def run_tests():
s = Solution()
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],
]
assert s.searchMatrix(matrix, 5) is True
assert s.searchMatrix(matrix, 20) is False
assert s.searchMatrix([[1]], 1) is True
assert s.searchMatrix([[1]], 2) is False
assert s.searchMatrix([[1, 3, 5]], 3) is True
assert s.searchMatrix([[1], [3], [5]], 4) is False
assert s.searchMatrix([[-5, -3, 0], [-2, 1, 4], [2, 6, 9]], -3) is True
print("all tests passed")
run_tests()| Test | Why |
|---|---|
Standard matrix, target 5 | Target exists |
Standard matrix, target 20 | Target missing |
[[1]], target 1 | Single-cell hit |
[[1]], target 2 | Single-cell miss |
| Single row | Horizontal movement |
| Single column | Vertical movement |
| Negative values | General integer handling |