Last Updated: March 29, 2026
We have a square matrix where each row is sorted left to right and each column is sorted top to bottom. We need to find the kth smallest element overall. The tricky part is that while rows and columns are individually sorted, elements across different rows can interleave. For instance, the last element of row 0 might be larger than the first element of row 2.
The key observation is that the matrix has a special structure: matrix[0][0] is always the global minimum and matrix[n-1][n-1] is always the global maximum. Every path moving right or down encounters non-decreasing values. This structure is similar to merging multiple sorted lists, and it also lends itself to binary search on the answer value.
1 <= n <= 300 → The matrix has at most 90,000 elements. O(n^2 log n) is about 1.5 million operations, which is comfortable. But the problem asks for better than O(n^2) memory.-10^9 <= matrix[i][j] <= 10^9 → Values span a huge range, but binary search between matrix[0][0] and matrix[n-1][n-1] handles this efficiently.All rows and columns sorted → We can treat each row as a sorted list for heap merging, and count elements <= a value in O(n) time using staircase traversal.The simplest approach: dump every element into a flat list, sort it, and pick the (k-1)th element. This completely ignores the sorted structure of the matrix, but it's the most obvious starting point and guaranteed to be correct.
k - 1.This approach works but ignores the sorted structure entirely and uses O(n^2) memory. Since each row is already sorted, what if we treated this as merging k sorted lists with a min-heap?
Think of the matrix as n sorted lists (one per row). Finding the kth smallest across n sorted lists is a classic problem: use a min-heap. Start by pushing the first element of every row into the heap. Then extract the minimum k times. Each time you extract an element from row i, push the next element in that row (if it exists).
This is the exact same technique used in "Merge K Sorted Lists" (LeetCode #23). The heap always contains at most n elements (one per row), so each push/pop is O(log n). We do this k times, giving us O(k log n).
The heap always contains the smallest unprocessed element from each active row. When we pop the global minimum, we know nothing smaller remains unprocessed, because every row's smallest remaining element is in the heap. By pushing the next element from the same row, we maintain this invariant. After k pops, we've found the kth smallest element.
This is essentially a k-way merge. Instead of merging all n rows completely, we stop after k extractions.
(value, row, col).The heap approach works well but depends on k. When k is close to n^2, we do nearly n^2 heap operations. What if we binary searched on the answer value instead, leveraging both row and column sorting?
Instead of finding the kth element by extracting elements in order, we binary search on what the answer value could be. The search space is the range [matrix[0][0], matrix[n-1][n-1]], the smallest to largest values in the matrix.
For a candidate value mid, we count how many elements in the matrix are <= mid. If the count is >= k, the answer is mid or something smaller, so we search left. If the count < k, we need a larger value, so we search right.
The counting step is where the sorted structure really shines. Starting from the bottom-left corner of the matrix, if the current element is <= mid, the entire column above it (including itself) is also <= mid (because the column is sorted). So we add row + 1 to the count and move right. If the current element is > mid, we move up. This staircase traversal counts all elements <= mid in O(n) time.
low = matrix[0][0] and high = matrix[n-1][n-1].low < high:mid = low + (high - low) / 2.high = mid (answer could be mid or smaller).low = mid + 1 (answer must be larger).low.