There are two sorted arrays A and B of size m and n respectively. Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
Best Solution by Binary Search:
Before writting codes, we should understand the following things:
- The median of any ascending array is (num[ceiling((len-1)/2)]+num[ceiling(len/2)])/2. Mark cut (l,r)=(num[ceiling((len-1)/2)],num[ceiling(len/2)])/2).
- For two sorted arrays, the corresponding cuts are cut1(l1,r1), cut2(l2,r2). If l1<=r2 and l2<=r1, the final median is (max(l1,l2)+min(r1,r2))/2
- However, item 2 won't always happen. If we adjust cut1 to one direction and cut2 to opposite direction until l1<=r2 and l2<=r1, we could stil find the final median (max(l1,l2)+min(r1,r2))/2
- Initially, cut1(l1,r1)=(num[ceiling((len1-1)/2)],num[ceiling(len1/2)])/2), cut2(l2,r2)=(num[ceiling((len2-1)/2)],num[ceiling(len2/2)])/2), final merged array cut is (num[ceiling((len1+len2-1)/2)],num[ceiling((len1+len2)/2)])/2). The question is that if updated (l1,r1) is (num[ceiling((len1-1-x)/2)],num[ceiling((len1-x)/2)])/2), what's updated cut2 to ensure (l1,r1), (l2,r2) could find the final median? The answer is updated cut2 = (num[ceiling((len2+x-1)/2)],num[ceiling((len2+x)/2)])/2), which could be understanded as move x elements from array1 to array2 but the final median won't change
- Consider some corner cases:
- So the task becomes how to find appropriate cut index (ceiling((len1-1-x)/2), ceiling((len1-x)/2)) in order to make l1<=r2 and l2<=r1, we could do binary search ref to https://blog.youkuaiyun.com/taoqick/article/details/23260157. Understand the range of start+off is closed interval [0, len]
- (ceiling((len-1)/2), ceiling((len1)/2)) and (ceiling((len1)/2), ceiling((len1+1)/2)) are different and look like walking half step. It seems that we move left leg with one step and draw close the other leg. In order to support the half step and ceiling((len1-1)/2 ranging in closed interval [-1, len1-1], the search range for len1 should be closed [0,2len1]. We could finish the codes now.
import sys
class Solution:
def findMedianSortedArrays(self, nums1, nums2):
n1, n2 = len(nums1), len(nums2)
if (n1 < n2):
return self.findMedianSortedArrays(nums2, nums1)
#You may assume nums1 and nums2 cannot be both empty
left, right = 0, n2*2
l1_i,r1_i,l2_i,r2_i = 0,0,0,0
while (left <= right):
mid = left+(right-left)//2 #range from [0, 2*n2]
l2_i,r2_i = (mid-1)//2, mid//2 #l2_i ranges from [-1, n2-1], r2_i ranges from [0, n2]
l1_i,r1_i = (n1+n2-mid-1)//2, (n1+n2-mid)//2 #l1_i ranges from [-1, n1-1], r1_i ranges from [0, n1]
l2, r2 = nums2[l2_i] if l2_i >= 0 else -sys.maxsize, nums2[r2_i] if r2_i < n2 else sys.maxsize
l1, r1 = nums1[l1_i] if l1_i >= 0 else -sys.maxsize, nums1[r1_i] if r1_i < n1 else sys.maxsize
if (l1 > r2):
left = mid+1
elif (l2 > r1):
right = mid-1
else:
return (max(l1, l2) + min(r1, r2)) / 2
return (max(l1,l2) + min(r1,r2)) / 2
s = Solution()
print(s.findMedianSortedArrays([1,3],[2,4,5]))
print(s.findMedianSortedArrays([3,4,5,6],[1,2,3]))
print(s.findMedianSortedArrays([1,2],[3]))
print(s.findMedianSortedArrays([1,2],[3,4]))
print(s.findMedianSortedArrays([2,3,4],[1]))
Another solution:
The method of finding the kth number is easier than http://leetcode.com/2011/03/median-of-two-sorted-arrays.html .
Take notice of A[pa - 1] instead of A[pa] because pa >= 1
class Solution {
public:
double findKth(int A[], int m, int B[], int n, int k) {
if (m > n)
return findKth(B, n, A, m, k);
if (m == 0)
return B[k-1];
if (k == 1)
return min(A[0], B[0]);
int pa = min(m, k/2);
int pb = k - pa;
if (A[pa - 1] < B[pb - 1])
return findKth(A + pa, m - pa, B, n , k - pa);
else if (A[pa - 1] > B[pb - 1])
return findKth(A, m, B + pb, n - pb, k - pb);
else
return A[pa - 1];
}
double findMedianSortedArrays(int A[], int m, int B[], int n) {
int total = m + n;
if (total % 2 == 0)
return (findKth(A, m, B, n, total/2) + findKth(A, m, B, n, total/2 + 1))/2;
else
return findKth(A, m, B, n, total/2 + 1);
}
};