GeeksforGeeks Medium

Matrix Median

Rows of the matrix are sorted. Find the overall median without flattening (odd element count).

binary-searchmatrix
Open on GeeksforGeeks ↗
02

Intuition

The median is the smallest value with more than half the elements ≤ it. 'How many elements ≤ x' is countable fast — binary search each sorted row — and it's monotone in x, so binary search the value range for the first x whose count exceeds n·m/2.

How to spot this pattern

Same binary-search-the-answer idea, but the predicate counts rather than places. You search over values, and for each guess ask how many entries are ≤ it — cheap, because every row is sorted and answers in O(log m). Recognise the trick: when the whole structure is too big to merge, count against a guess instead.

03

Approach

1

Binary search on value, not position

Search lo=min(first column) to hi=max(last column). No element order across rows needed.

2

Count ≤ mid per row

Each sorted row answers 'how many ≤ mid' via bisect in O(log m); total count in O(n log m).

3

First value passing half wins

If count ≤ half, median is bigger → lo = mid+1; else hi = mid. Loop converges on the median itself (it must be present because counts jump only at matrix values).

04

Solution & live demo

1from bisect import bisect_right
2 
3def matrix_median(mat):
4 n, m = len(mat), len(mat[0])
5 lo = min(row[0] for row in mat)
6 hi = max(row[-1] for row in mat)
7 need = (n * m) // 2
8 while lo < hi:
9 mid = (lo + hi) // 2
10 count = sum(bisect_right(row, mid) for row in mat)
11 if count <= need: lo = mid + 1
12 else: hi = mid
13 return lo
05

Common pitfalls

Merging all rows and sorting

✗ Wrong
flat = sorted(x for row in mat for x in row)
return flat[(n * m) // 2]
✓ Right
count = sum(bisect_right(row, mid) for row in mat)

Correct, but O(nm log nm) time and O(nm) space when the rows are already sorted. Binary searching values costs O(n log m log(range)) and allocates nothing.

Using bisect_left for the count

✗ Wrong
count = sum(bisect_left(row, mid) for row in mat)
✓ Right
count = sum(bisect_right(row, mid) for row in mat)

You need the number of elements less than or equal to mid. bisect_left excludes elements equal to it, so every duplicate of the candidate goes uncounted and the search settles one value too low.

Terminating with lo <= hi and returning mid

✗ Wrong
while lo <= hi:
    ...
    return mid
✓ Right
while lo < hi:
    ...
return lo

The median must be an element that actually appears, and a mid satisfying the count condition need not be one. Converging with lo < hi and returning lo lands on a real matrix entry.

06

Edge cases

Single row

Median is the middle of that row — the search still lands there.

Heavy duplicates

Counting ≤ handles ties naturally; convergence lands on the duplicated value.

07

Complexity

Time
O(n log m · log R)
Space
O(1)
R = value range; counting is n rows × log m.