Lesson 26 of 164
Median of Two Sorted Arrays of the Same Size
Given two sorted arrays a and b, both of length n >= 1, return the median of all 2n values. Because 2n is even, the median is the mean of the two middle values.
Example
a = [1, 3], b = [2, 4] Output: 2.5 (merged: 1 2 3 4)
a = [1, 2, 9], b = [3, 4, 7] Output: 3.5 (merged: 1 2 3 4 7 9)The general version with different lengths is LeetCode 4.
Brute force: merge up to the middle
Merge the two arrays as in merge sort, but stop after the two middle positions, n - 1 and n.
public class Main {
static double median(int[] a, int[] b) {
int n = a.length;
int i = 0;
int j = 0;
int prev = 0;
int cur = 0;
for (int step = 0; step <= n; step++) {
prev = cur;
if (j == n || (i < n && a[i] <= b[j])) {
cur = a[i++];
} else {
cur = b[j++];
}
}
return ((double) prev + cur) / 2.0;
}
public static void main(String[] args) {
System.out.println(median(new int[] {1, 3}, new int[] {2, 4}) + " " + median(new int[] {1, 2, 9}, new int[] {3, 4, 7}));
}
}2.5 3.5Time: O(n). Space: O(1).
Optimal: binary search for the partition
Take i elements from the front of a and n - i from the front of b. Together they are the lower half of the merged array exactly when every taken element is at most every element left behind:
a[i - 1] <= b[n - i] and b[n - i - 1] <= a[i](Each array's own elements are already in order.) Binary search i over 0 to n. If a[i - 1] > b[n - i], too much of a was taken, so move left. If b[n - i - 1] > a[i], too little, so move right. At the right partition, the two middle values are the largest taken element and the smallest remaining one.
For a = [1, 2, 9], b = [3, 4, 7]:
| i | taken from a | taken from b | check | result |
|---|---|---|---|---|
| 1 | [1] | [3, 4] | b's 4 > a's 2 | take more of a |
| 2 | [1, 2] | [3] | 2 <= 4 and 3 <= 9 | found: max(2, 3) = 3, min(9, 4) = 4 |
Missing neighbours at the ends (i = 0 or i = n) are treated as negative infinity on the left and positive infinity on the right. double values print with a decimal point, so the median 7 prints as 7.0.
public class Main {
static double median(int[] a, int[] b) {
int n = a.length;
int lo = 0;
int hi = n;
while (true) {
int i = lo + (hi - lo) / 2; // take i from a, n - i from b
int j = n - i;
long aLeft = i > 0 ? a[i - 1] : Long.MIN_VALUE;
long aRight = i < n ? a[i] : Long.MAX_VALUE;
long bLeft = j > 0 ? b[j - 1] : Long.MIN_VALUE;
long bRight = j < n ? b[j] : Long.MAX_VALUE;
if (aLeft > bRight) {
hi = i - 1;
} else if (bLeft > aRight) {
lo = i + 1;
} else {
long lower = Math.max(aLeft, bLeft);
long upper = Math.min(aRight, bRight);
return (lower + upper) / 2.0;
}
}
}
public static void main(String[] args) {
System.out.println(median(new int[] {1, 3}, new int[] {2, 4}) + " " + median(new int[] {1, 2, 9}, new int[] {3, 4, 7}));
System.out.println(median(new int[] {1, 2}, new int[] {3, 4}) + " " + median(new int[] {5, 6}, new int[] {1, 2}));
System.out.println(median(new int[] {7}, new int[] {7}));
}
}2.5 3.5
2.5 3.5
7.0Time: O(log n). Space: O(1).
hi = i - 1 never makes hi negative: aLeft > bRight needs a real a[i - 1], so i >= 1. A valid partition always exists, so the loop always returns. The sentinels are Long.MIN_VALUE and Long.MAX_VALUE, so they stay outside the range of every int element.
Edge cases
- All of
ais smaller thanb: the partition isi = n; the middle values area[n - 1]andb[0]. - Equal values across arrays: the checks use
<=, so ties are fine. - Overflow: adding two
intvalues can wrap around. The code widens tolong(ordouble) before adding, so the sum is exact.
