Median of a Row-wise Sorted Matrix
Problem
A matrix has r rows and c columns, with r * c odd. Each row is sorted from small to large (the columns are not sorted). Print the median of all the numbers: the middle one after sorting all r * c numbers.
Constraints
- 1 <= r, c <= 100
- r * c is odd
- 1 <= value <= 10^9
Examples
Input
3 3 1 3 5 2 6 9 3 6 9
Output
5
Solutions
Sorting everything costs O(r c log(r c)). Instead we guess a value and count how many numbers are at most that value, using the sorted rows. The median is the smallest value that has more than half of the numbers at or below it.
/*
* Problem : Find the median.
* Input : r, c and the rows.
* Output : The median.
* Approach: Binary search on the value
* Time : O(r log(c) log(range))
* Space : O(1)
* Java : 8 or newer.
*/
import java.util.Scanner;
public class Main {
// This method solves the task. It receives the input and returns the answer.
static long solve(int[][] m) {
int rows = m.length;
int cols = m[0].length;
// Step 1: The median is a value between the smallest and the biggest number. Search for it with binary search on the value.
long low = Long.MAX_VALUE;
long high = Long.MIN_VALUE;
for (int[] row : m) {
low = Math.min(low, row[0]);
high = Math.max(high, row[cols - 1]);
}
long wanted = (long) rows * cols / 2;
while (low < high) {
long mid = low + (high - low) / 2;
// Step 2: Count how many numbers are <= mid. Every row is sorted, so a binary search per row is enough.
long count = 0;
for (int[] row : m) {
int left = 0;
int right = cols;
while (left < right) {
int middle = (left + right) / 2;
if (row[middle] <= mid) {
left = middle + 1;
} else {
right = middle;
}
}
count += left;
}
// Step 3: The median is the smallest value with more than "wanted" numbers at or below it.
if (count <= wanted) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
int rows = scanner.nextInt();
int cols = scanner.nextInt();
int[][] m = new int[rows][cols];
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
m[i][j] = scanner.nextInt();
}
}
System.out.println(solve(m));
}
}
Hints (2)
- How can sorted rows count fast?
- What is monotonic here?