Problem
There are two sorted arrays nums1 and nums2 of size n. Find the median of the two sorted arrays.
You may assume nums1 and nums2 cannot be both empty.
OR There are 2 sorted arrays A and B. Write an algorithm to find the median of the array obtained after merging the above 2 arrays(i.e. array of length 2n). The complexity should be O(log(n))
Median Definition
Note → Since the size of the two input arrays for which we are looking for the median is even(2n), we need to take the average of the middle two numbers and return it.
Examples
Example 1:
nums1 = [1, 3]
nums2 = [2, 4]
The median is 2.5 as (2 + 3) / 2 = 2.5
Example 2:
nums1 = [1, 2, 9]
nums2 = [3, 4, 7]
The median is (3 + 4)/2 = 3.5
Solution
Method 1 - Brute Force
We can combine two arrays into a sorted array in O(n)
time and then calculate the average of the middle two values. However, this approach is not efficient enough.
Method 2 - Counting While Comparing (kind of Brute force)
- Initialise two pointers,
i
andj
, to 0, pointing to the start ofnums1
andnums2
, respectively. - Compare the values at
nums1[i]
andnums2[j]
; ifnums1[i]
is smaller, incrementi
; otherwise, incrementj
. - Continue step 2 until the sum of
i
andj
equalsn
. - Finally, return the median of the elements at the
i-th
andj-th
indexes.
Code
Java
int getMedian(int arr1[], int arr2[]) {
int n = arr1.length;
int i = 0; // Current index of array arr1[]
int j = 0; // Current index of array arr2[]
int count;
int m1 = -1, m2 = -1;
//Since there are 2n elements, median will be average
// of elements at index n-1 and n in the array obtained after
// merging ar1 and ar2
for (count = 0; count<= n; count++) {
//Below is to handle case where all elements of arr1[] are
// smaller than smallest(or first) element of arr2[]
if (i == n) {
m1 = m2;
m2 = arr2[0];
break;
}
//Below is to handle case where all elements of arr2[] are
// smaller than smallest(or first) element of arr1[]
else if (j == n) {
m1 = m2;
m2 = arr1[0];
break;
}
if (arr1[i]<arr2[j]) {
m1 = m2; //Store the prev median
m2 = arr1[i];
i++;
} else {
m1 = m2; //Store the prev median
m2 = arr2[j];
j++;
}
}
return (m1 + m2) / 2;
}
Complexity
- ⏰ Time complexity:
O(n)
wheren
is the size of the input arrays - 🧺 Space complexity:
O(1)
Method 3 - Comparing Medians - Divide and Conquer
This method involves comparing the medians of both arrays using the Divide & Conquer approach. Let us denote the medians by m1
and m2
.
- If
m1 > m2
, then the median will be in the union ofnums1[0 to m1]
andnums2[m2 to n]
. This means we search for the median withinnums1
from the beginning tomedian1
and withinnums2
frommedian2
to the end. (Why?)
To sum up:
if (m1 > m2) {
Take the left half of arr1 and the right half of arr2.
} else {
Take the right half of arr1 and the left half of arr2.
}
We know median1
is at least as large as the first half of nums1
, and similarly for median2
and nums2
. We also know median1
is at most as large as the second half of nums1
.
Consider the case where median1 > median2
:
nums1: [.....median1.....]
nums2: [.....median2.....]
nums1+nums2: [.....median2...median1........]
Example
nums1 = {1, 12, 15, 26, 38}
nums2 = {2, 13, 17, 30, 45}
m1 = 15 and m2 = 17 for num1[0 to 4] and num2[0 to 4]
m1 < m2. So, the median is within {15, 26, 38} and {2, 13, 17}
Now, m1 = 26 and m2 = 13
m1 > m2. So, the median is within {15, 26} and {13, 17}
When both subarrays size is 2:
Median = (max(15, 13) + min(26, 17)) / 2 = 16
Algorithm
Calculate the medians
m1
andm2
ofnum1[]
andnum2[]
.Repeat until the size of
num1
andnum2
is two.- If
m1 == m2
, return m1. - If
m1 > m2
, the median is innum1[0..m1]
andnum2[m2 to n]
. - If
m2 > m1
, the median is innum1[m1 to n]
andnum2[0 to m2]
.
- If
Return
Median = (max(array1[0], array2[0]) + min(array1[1], array2[1])) / 2
.
Code
Java
public class MedianOfTwoSortedArrays {
public double findMedianEqualSize(int[] nums1, int[] nums2) {
int n = nums1.length;
return helper(nums1, nums2, 0, 0, n);
}
private double helper(int[] nums1, int[] nums2, int start1, int start2, int n) {
// Base cases when the size of both arrays is 2
if (n == 1) {
return (nums1[start1] + nums2[start2]) / 2.0;
}
if (n == 2) {
return (Math.max(nums1[start1], nums2[start2]) + Math.min(nums1[start1 + 1], nums2[start2 + 1])) / 2.0;
}
int m1 = getMedian(nums1, start1, n);
int m2 = getMedian(nums2, start2, n);
if (m1 == m2) {
return m1;
}
if (m1 < m2) {
if (n % 2 == 0) {
return helper(nums1, nums2, start1 + n / 2 - 1, start2, n - n / 2 + 1);
} else {
return helper(nums1, nums2, start1 + n / 2, start2, n - n / 2);
}
} else {
if (n % 2 == 0) {
return helper(nums1, nums2, start1, start2 + n / 2 - 1, n - n / 2 + 1);
} else {
return helper(nums1, nums2, start1, start2 + n / 2, n - n / 2);
}
}
}
private int getMedian(int[] nums, int start, int n) {
if (n % 2 == 0) {
return (nums[start + n / 2] + nums[start + n / 2 - 1]) / 2;
} else {
return nums[start + n / 2];
}
}
}
Complexity
- ⏰ Time complexity:
O(log n)
, wheren
is length of array, as we compare the medians of the two arrays and then recursively reduce the problem size. - 🧺 Space complexity:
O(log n)
, assuming recursion stack