MediumBinary Search

Search a 2D Matrix II โ€” Solution

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.

  1. Iterate over each row.
  2. Iterate over each element in the row.
  3. Return true if the element equals the target.
  4. 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 False

Time: 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.

  1. Position row = 0, col = numCols - 1 (top-right corner).
  2. While row and col are in bounds, read current = matrix[row][col].
  3. If current == target, return true.
  4. If current > target, decrement col โ€” the entire current column is ruled out.
  5. If current < target, increment row โ€” the entire current row is ruled out.
  6. 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 False

Time: 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

ApproachTimeSpaceWhen to use
Brute ForceO(mยทn)O(1)Acceptable when the matrix is tiny and code simplicity matters
Staircase SearchO(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 > target from 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, not col < numCols. After starting at numCols - 1 and only decrementing, the valid range is [0, numCols-1]; the out-of-bounds exit is col < 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 here
  • kth-smallest-element-in-a-sorted-matrix โ€” same row-and-column sorted matrix; uses binary search on the value range
  • find-peak-element โ€” another problem where a smart pointer eliminates half the search space without brute-forcing
  • binary-search โ€” the foundational operation; row-level binary search is a valid O(m log n) middle ground for this problem
  • search-in-rotated-sorted-array โ€” similarly exploits structural guarantees to avoid a full scan

Ready to practice? Try it on SkillFlow

Adaptive problems, AI follow-up interviews, and a skill score that shows exactly where you need to improve.

Practice This Problem โ†’