Skip to content
DSAPrep

    ↑↓ to move · Enter to open · Esc to close

    Search a 2D Matrix

    You are given an m x n integer matrix matrix with the following two properties:

    Each row is sorted in non-decreasing order. The first integer of each row is greater than the last integer of the previous row.

    Given an integer target, return true if target is in matrix or false otherwise.

    You must write a solution in O(log(m * n)) time complexity.

    Example 1

    Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3

    Output: true

    Example 2

    Input: matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 13

    Output: false

    Constraints

    • m == matrix.length
    • n == matrix[i].length
    • 1 <= m, n <= 100
    • -10^4 <= matrix[i][j], target <= 10^4
    View original on LeetCode ↗

    Row-by-Row Scan

    Time O(m + n)Space O(1)

    Start at the top-right corner. If the current value is bigger than the target, the whole column below it is also too big (columns are sorted), so move left. If it is smaller, the whole row to the left is too small, so move down. This staircase walk touches each row and column at most once, but it never uses the fact that the rows are laid out end-to-end into one giant sorted sequence — which is exactly what lets us do better.

    class Solution:
    def searchMatrix(self, matrix: list[list[int]], target: int) -> bool:
    row, col = 0, len(matrix[0]) - 1
    while row < len(matrix) and col >= 0:
    val = matrix[row][col]
    if val == target:
    return True
    elif val > target:
    col -= 1
    else:
    row += 1
    return False

    Binary Search on the Flattened Matrix

    OptimalTime O(log(m * n))Space O(1)

    Because the last element of every row is smaller than the first element of the next row, the matrix is really just a sorted 1D array of m * n elements split into rows of length n. We can binary search over the flattened indices 0 .. m*n - 1 directly, without ever building the flattened array: a flat index mid maps to matrix[mid // n][mid % n].

    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) // 2
    val = matrix[mid // n][mid % n]
    if val == target:
    return True
    elif val < target:
    lo = mid + 1
    else:
    hi = mid - 1
    return False

    Tracing matrix = [[1,3,5,7],[10,11,16,20],[23,30,34,60]], target = 3:

    Watch how a flat mid index becomes a matrix row and column, and how one comparison throws away half of the flattened array.

    1#0
    3#1
    5#2
    7#3
    10#4
    11#5
    16#6
    20#7
    23#8
    30#9
    34#10
    60#11
    lo = 0mid = —hi = 11
    row = — = ?col = — = ?
    1 / 8
    comparingresultdiscarded

    Row by row the matrix is one sorted array of 12. Each cell shows its flat index, so the window starts as lo = 0 to hi = 11.

    Why it’s correct: the two given properties are exactly what is needed to guarantee that reading the matrix row by row produces a fully sorted sequence, so mapping flat index i to matrix[i // n][i % n] reproduces ordinary binary search over that sequence. Complexity: the search window over m * n elements halves every step, giving O(log(m * n)) time, O(1) space.

    More Binary Search practice