Find median in row wise sorted matrix
Last Updated :
13 Aug, 2025
Given a row-wise sorted matrix mat[][] with an odd number of rows and columns, find the median of the matrix.
Note: The median is defined as the middle element in the sorted list of all elements in the matrix. Since the total number of elements is always odd, the median is guaranteed to exist and be unique.
Examples:
Input: mat[][] = [[1 3 5],
[2 6 9],
[3 6 9]]
Output: 5
Explanation: Elements in sorted order: 1 2 3 3 5 6 6 9 9. There are total 9 elements, thus the median is the element at index 5 (1-based) i.e. 5.
Input: mat[][] = [[1 3 4],
[2 5 6]
[3 7 9]]
Output: 4
Explanation: Elements in sorted order: 1 2 3 3 4 5 6 7 9. There are total 9 elements, thus the median is the element at index 5 (1-based) i.e. 4.
The idea is to first flatten the 2D matrix into a 1D array by collecting all its elements. Then, the array is sorted to bring all elements into order. Since the total number of elements is odd, the median is the middle element of the sorted array.
C++
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;
int median(vector<vector<int>> &mat) {
// flatten the matrix into a 1-dimensional array
vector<int> arr;
for (int i = 0; i < mat.size(); i++) {
for (int j = 0; j < mat[0].size(); j++) {
arr.push_back(mat[i][j]);
}
}
// sort the array
sort(arr.begin(), arr.end());
// find the median element
int mid = arr.size() / 2;
return arr[mid];
}
int main() {
vector<vector<int>> matrix =
{{1, 3, 5},
{2, 6, 9},
{3, 6, 9}};
cout << median(matrix) << endl;
return 0;
}
Java
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
class GfG {
static int median(int mat[][]) {
// flatten the matrix into a 1D array
List<Integer> list = new ArrayList<>();
for (int i = 0; i < mat.length; i++) {
for (int j = 0; j < mat[0].length; j++) {
list.add(mat[i][j]);
}
}
// sort the list
Collections.sort(list);
// find and return the median element
int mid = list.size() / 2;
return list.get(mid);
}
public static void main(String[] args) {
int[][] matrix = {
{1, 3, 5},
{2, 6, 9},
{3, 6, 9}
};
System.out.println(median(matrix));
}
}
Python
def median(mat):
# flatten the matrix into a 1D array
arr = []
for i in range(len(mat)):
for j in range(len(mat[0])):
arr.append(mat[i][j])
# sort the array
arr.sort()
# find the median element
mid = len(arr) // 2
return arr[mid]
if __name__ == "__main__":
mat = [[1, 3, 5],
[2, 6, 9],
[3, 6, 9]]
print(median(mat))
C#
using System;
using System.Collections.Generic;
using System.Linq;
class GfG {
static int median(int[][] mat) {
// flatten the matrix into a 1D list
List<int> arr = new List<int>();
for (int i = 0; i < mat.Length; i++) {
for (int j = 0; j < mat[i].Length; j++) {
arr.Add(mat[i][j]);
}
}
// sort the array
arr.Sort();
// find the median element
int mid = arr.Count / 2;
return arr[mid];
}
static void Main(string[] args) {
int[][] mat = new int[][] { new int[] { 1, 3, 5 },
new int[] { 2, 6, 9 },
new int[] { 3, 6, 9 } };
Console.WriteLine(median(mat));
}
}
JavaScript
function median(mat) {
// flatten the matrix into a 1D array
const arr =
mat.reduce((acc, row) => acc.concat(row), []);
// sort the array
arr.sort((a, b) => a - b);
// find the median element
const mid = Math.floor(arr.length / 2);
return arr[mid];
}
// Driver Code
const mat = [
[1, 3, 5],
[2, 6, 9],
[3, 6, 9]
];
console.log(median(mat));
[Better Approach] Using Priority Queue
The idea is to use a min-heap–like structure to efficiently find the median without flattening or sorting the entire matrix. Since each row is already sorted, we start by inserting the first element of each row into a heap (simulated with a sorted map). Then we repeatedly extract the smallest element and push the next element from the same row, simulating the merging of sorted rows. This continues until we reach the median position. It avoids full sorting and leverages the sorted rows for efficiency.
C++
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
int median(vector<vector<int>> &mat) {
int rows = mat.size();
int cols = mat[0].size();
// min-heap storing {value, row, col}
priority_queue<vector<int>,
vector<vector<int>>, greater<vector<int>>> minHeap;
int medianIndex = (rows * cols) / 2;
int count = 0, result = -1;
// push the first element of each row into the min-heap
for (int i = 0; i < rows; i++) {
minHeap.push({mat[i][0], i, 0});
}
// extract the smallest elements until reaching the median
while (count <= medianIndex) {
vector<int> top = minHeap.top();
minHeap.pop();
int val = top[0], row = top[1], col = top[2];
result = val;
count++;
// if more elements are left in the current
// row, push next
if (col + 1 < cols) {
minHeap.push({mat[row][col + 1], row, col + 1});
}
}
return result;
}
int main() {
vector<vector<int>> matrix = {
{1, 3, 5},
{2, 6, 9},
{3, 6, 9}
};
cout << median(matrix) << endl;
return 0;
}
Java
import java.util.PriorityQueue;
import java.util.Comparator;
class GfG {
public static int median(int[][] mat) {
int rows = mat.length;
int cols = mat[0].length;
// min-heap storing {value, row, col}
PriorityQueue<int[]> minHeap =
new PriorityQueue<>(Comparator.comparingInt(a -> a[0]));
int medianIndex = (rows * cols) / 2;
int count = 0, result = -1;
// push the first element of each row into the min-heap
for (int i = 0; i < rows; i++) {
minHeap.add(new int[]{mat[i][0], i, 0});
}
// extract the smallest elements until reaching the median
while (count <= medianIndex) {
int[] top = minHeap.poll();
int val = top[0], row = top[1], col = top[2];
result = val;
count++;
// if more elements are left in the current
// row, push next
if (col + 1 < cols) {
minHeap.add(new int[]{mat[row][col + 1],row,col + 1});
}
}
return result;
}
public static void main(String[] args) {
int[][] matrix = {
{1, 3, 5},
{2, 6, 9},
{3, 6, 9}
};
System.out.println(median(matrix));
}
}
Python
import heapq
def median(mat):
rows = len(mat)
cols = len(mat[0])
# min-heap storing [value, row, col]
minHeap = []
medianIndex = (rows * cols) // 2
count = 0
result = -1
# push the first element of each row into
# the min-heap
for i in range(rows):
heapq.heappush(minHeap, [mat[i][0], i, 0])
# extract the smallest elements until reaching
# the median
while count <= medianIndex:
val, row, col = heapq.heappop(minHeap)
result = val
count += 1
# if more elements are left in the current
# row, push next
if col + 1 < cols:
heapq.heappush(minHeap, \
[mat[row][col + 1], row, col + 1])
return result
if __name__ == "__main__":
matrix = [
[1, 3, 5],
[2, 6, 9],
[3, 6, 9]
]
print(median(matrix))
C#
using System;
using System.Collections.Generic;
class GfG {
class Position {
public int row;
public int col;
public Position(int r, int c) {
row = r;
col = c;
}
}
public static int median(int[][] mat) {
int rows = mat.Length;
int cols = mat[0].Length;
// simulate min-heap using SortedDictionary
SortedDictionary<int, Queue<Position>> heap =
new SortedDictionary<int, Queue<Position>>();
int medianIndex = (rows * cols) / 2;
int count = 0, result = -1;
// push the first element of each row into the map
for (int i = 0; i < rows; i++) {
int val = mat[i][0];
if (!heap.ContainsKey(val))
heap[val] = new Queue<Position>();
heap[val].Enqueue(new Position(i, 0));
}
// extract the smallest elements until reaching the median
while (count <= medianIndex) {
int minKey = getFirstKey(heap);
Position pos = heap[minKey].Dequeue();
if (heap[minKey].Count == 0)
heap.Remove(minKey);
result = minKey;
count++;
int row = pos.row;
int col = pos.col;
// push next element in the same row if it exists
if (col + 1 < cols) {
int nextVal = mat[row][col + 1];
if (!heap.ContainsKey(nextVal))
heap[nextVal] = new Queue<Position>();
heap[nextVal].Enqueue(new Position(row, col + 1));
}
}
return result;
}
private static int getFirstKey
(SortedDictionary<int, Queue<Position>> map) {
foreach (var kvp in map)
return kvp.Key;
return -1; // should never reach
}
public static void Main(string[] args) {
int[][] matrix = new int[][] {
new int[] {1, 3, 5},
new int[] {2, 6, 9},
new int[] {3, 6, 9}
};
Console.WriteLine(median(matrix));
}
}
JavaScript
function median(mat) {
const rows = mat.length;
const cols = mat[0].length;
// min-heap storing [value, row, col]
const minHeap = [];
const medianIndex=Math.floor((rows * cols) / 2);
let count = 0, result = -1;
// push the first element of each row into
// the min-heap
for (let i = 0; i < rows; i++) {
minHeap.push([mat[i][0], i, 0]);
}
minHeap.sort((a, b)=>a[0] - b[0]);
// extract the smallest elements until
// reaching the median
while (count <= medianIndex) {
const [val, row, col] = minHeap.shift();
result = val;
count++;
// if more elements are left in the current
// row, push next
if (col + 1 < cols) {
minHeap.push([mat[row][col + 1],row,col + 1]);
minHeap.sort((a, b) => a[0] - b[0]);
}
}
return result;
}
// Driver Code
const matrix = [
[1, 3, 5],
[2, 6, 9],
[3, 6, 9]
];
console.log(median(matrix));
Time complexity: O(n × m × log(n)), since we are going to insert and remove the top element in priority queue (n × m) / 2 times and every time the priority queue will be having elements in it.
Auxiliary Space: O(n), the min-heap stores at most one element per row of the matrix at any point in time.
[Expected Approach] Using Binary Search on Answer
The key idea is that for a number x to be the median in an n x m matrix, there must be exactly (n * m) / 2 elements less than or equal to x. We perform binary search over the range [minElement, maxElement], where minElement and maxElement are the smallest and largest elements in the matrix.
At each step, we compute the number of elements less than or equal to the current mid.
=> If this count is less than or equal to (n * m) / 2, we search in the upper half of the range to increase the candidate value.
=> Otherwise, we search in the lower half to reduce it
C++
#include <algorithm>
#include <iostream>
#include <climits>
#include <vector>
using namespace std;
int median(vector<vector<int>> &mat) {
int n = mat.size();
int m = mat[0].size();
int minVal = INT_MAX, maxVal = INT_MIN;
// finding the minimum and maximum elements
// in the matrix
for (int i = 0; i < n; i++) {
if (mat[i][0] < minVal)
minVal = mat[i][0];
if (mat[i][m - 1] > maxVal)
maxVal = mat[i][m - 1];
}
int desired = (n * m + 1) / 2;
int lo = minVal, hi = maxVal;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
int place = 0;
// count elements smaller than or equal to mid
for (int i = 0; i < n; ++i)
place +=
upper_bound(mat[i].begin(), mat[i].end(), mid)
- mat[i].begin();
// adjust the range based on the count of
// elements found
if (place < desired)
lo = mid + 1;
else
hi = mid;
}
return lo;
}
int main() {
vector<vector<int>> mat = {{1, 3, 5},
{2, 6, 9},
{3, 6, 9}};
cout << median(mat) << endl;
return 0;
}
Java
import java.util.Arrays;
class GfG {
static int median(int mat[][]) {
int n = mat.length;
int m = mat[0].length;
// initializing the minimum and maximum values
int min = Integer.MAX_VALUE,
max = Integer.MIN_VALUE;
// iterating through each row of the matrix
for (int i = 0; i < n; i++) {
// updating the minimum value if current
// element is smaller
if (mat[i][0] < min)
min = mat[i][0];
// updating the maximum value if current
// element is larger
if (mat[i][m - 1] > max)
max = mat[i][m - 1];
}
// calculating the desired position of the median
int desired = (n * m + 1) / 2;
// using binary search to find the median value
while (min < max) {
// calculating the middle value
int mid = min + (max - min) / 2;
// counting the number of elements less than
// or equal to mid
int place = 0;
for (int i = 0; i < n; i++) {
place += upperBound(mat[i], mid);
}
// updating the search range based on the count
if (place < desired) {
min = mid + 1;
} else {
max = mid;
}
}
// returning the median value
return min;
}
// helper function to find the upper bound of a
// number in a row
static int upperBound(int[] row, int num) {
int low = 0, high = row.length;
while (low < high) {
int mid = low + (high - low) / 2;
if (row[mid] <= num) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
public static void main(String[] args) {
int mat[][] = {{ 1, 3, 5 },
{ 2, 6, 9 },
{ 3, 6, 9 }};
System.out.println(median(mat));
}
}
Python
from bisect import bisect_right
def median(mat):
n = len(mat)
m = len(mat[0])
minVal = float('inf')
maxVal = float('-inf')
# finding the minimum and maximum elements
# in the matrix
for i in range(n):
minVal = min(minVal, mat[i][0])
maxVal = max(maxVal, mat[i][m - 1])
desired = (n * m + 1) // 2
lo = minVal
hi = maxVal
# binary search to find the median
while lo < hi:
mid = lo + (hi - lo) // 2
place = 0
# count elements smaller than or equal to mid
# using bisect_right
for i in range(n):
place += bisect_right(mat[i], mid)
if place < desired:
lo = mid + 1
else:
hi = mid
return lo
if __name__ == "__main__":
mat = [[1, 3, 5],
[2, 6, 9],
[3, 6, 9]]
print(median(mat))
C#
using System;
class GfG {
static int median(int[][] mat) {
int n = mat.Length;
int m = mat[0].Length;
// initializing the minimum and maximum values
int min = int.MaxValue, max = int.MinValue;
// iterating through each row of the matrix
for (int i = 0; i < n; i++) {
// updating the minimum value if current
// element is smaller
if (mat[i][0] < min)
min = mat[i][0];
// updating the maximum value if current element
// is larger
if (mat[i][m - 1] > max)
max = mat[i][m - 1];
}
// calculating the desired position of the median
int desired = (n * m + 1) / 2;
// using binary search to find the median value
int lo = min, hi = max;
while (lo < hi)
{
// calculating the middle value
int mid = lo + (hi - lo) / 2;
// counting the number of elements less than or
// equal to mid
int place = 0;
for (int i = 0; i < n; i++)
place += upperBound(mat[i], mid);
// updating the search range based on the count
if (place < desired)
lo = mid + 1;
else
hi = mid;
}
// returning the median value
return lo;
}
// helper function to find the upper bound of
// a number in a row
static int upperBound(int[] row, int num) {
int lo = 0, hi = row.Length;
while (lo < hi) {
int mid = lo + (hi - lo) / 2;
if (row[mid] <= num)
lo = mid + 1;
else
hi = mid;
}
return lo;
}
static void Main(string[] args) {
int[][] mat = new int[][] {
new int[] { 1, 3, 5 },
new int[] { 2, 6, 9 },
new int[] { 3, 6, 9 }
};
Console.WriteLine(median(mat));
}
}
JavaScript
function median(mat) {
const n = mat.length;
const m = mat[0].length;
// initializing the minimum and maximum values
let min = Number.MAX_VALUE, max = Number.MIN_VALUE;
// iterating through each row of the matrix
for (let i = 0; i < n; i++) {
// updating the minimum value if current element
// is smaller
if (mat[i][0] < min)
min = mat[i][0];
// updating the maximum value if current element
// is larger
if (mat[i][m - 1] > max)
max = mat[i][m - 1];
}
// calculating the desired position of the median
const desired = Math.floor((n * m + 1) / 2);
// using binary search to find the median value
let lo = min, hi = max;
while (lo < hi) {
// calculating the middle value
const mid = Math.floor(lo + (hi - lo) / 2);
// counting the number of elements less than or
// equal to mid
let place = 0;
for (let i = 0; i < n; i++) {
place += upperBound(mat[i], mid);
}
// updating the search range based on the count
if (place < desired) {
lo = mid + 1;
} else {
hi = mid;
}
}
// returning the median value
return lo;
}
// helper function to find the upper bound of a
// number in a row
function upperBound(row, num) {
let lo = 0, hi = row.length;
while (lo < hi) {
const mid = Math.floor(lo + (hi - lo) / 2);
if (row[mid] <= num) {
lo = mid + 1;
}
else {
hi = mid;
}
}
return lo;
}
// Driver Code
const mat = [
[1, 3, 5],
[2, 6, 9],
[3, 6, 9]
];
console.log(median(mat));
Time Complexity: O(n × log(m) × log(maxVal - minVal)), the upper bound function will take log(m) time and is performed for each row. And binary search is performed from minVal to maxVal.
Auxiliary Space: O(1)
Explore
DSA Fundamentals
Data Structures
Algorithms
Advanced
Interview Preparation
Practice Problem