package com.freetymekiyan.algorithms.level.hard;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
/**
* There are two sorted arrays nums1 and nums2 of size m and n respectively.
* <p>
* Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
* <p>
* Example 1:
* nums1 = [1, 3]
* nums2 = [2]
* <p>
* The median is 2.0
* Example 2:
* nums1 = [1, 2]
* nums2 = [3, 4]
* <p>
* The median is (2 + 3)/2 = 2.5
* <p>
* Tags: Binary Search, Array, Divide and Conquer
*/
public class MedianOfTwoSortedArrays {
private MedianOfTwoSortedArrays m;
/**
* Binary Search.
* First figure out what we are to search for.
* There are one cut point for each array, i for nums1, j for nums2.
* Then we have four smaller arrays: nums1[0 ~ i - 1], nums2[0 ~ j - 1], nums1[i, m - 1], nums2[j, n - 1]
* If we name them A, B, C, D, respectively, then the desired values for i and j should make:
* 1) len(A) + len(B) = len(C) + len(D) => i + j = m + n - i - j or m + n + 1 - i - j
* 2) nums1[i - 1] <= nums2[j] && nums2[j - 1] <= nums1[i]
* <p>
* If the # of elements is odd, the median is max(A, B)
* If even, the median is (max(A, B) + min(C, D)) / 2
* <p>
* https://discuss.leetcode.com/topic/4996/share-my-o-log-min-m-n-solution-with-explanation/2
*/
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int m = nums1.length;
int n = nums2.length;
if (m > n) {
return findMedianSortedArrays(nums2, nums1); // Keep shorter array first
}
int i = 0;
int j = 0;
int iMin = 0;
int iMax = m;
int mid = (m + n + 1) / 2; // m <= n
while (iMin <= iMax) {
i = (iMin + iMax) / 2;
j = mid - i;
if (j > 0 && i < m && nums2[j - 1] > nums1[i]) {
// i is too small
iMin = i + 1;
} else if (i > 0 && j < n && nums1[i - 1] > nums2[j]) {
// i is too big
iMax = i - 1;
} else {
break;
}
}
int leftMax = 0;
if (i == 0) {
leftMax = nums2[j - 1];
} else if (j == 0) {
leftMax = nums1[i - 1];
} else {
leftMax = Math.max(nums1[i - 1], nums2[j - 1]);
}
if ((m + n) % 2 == 1) { // Total # of elements is odd
return leftMax;
}
int rightMin = 0; // Total # of elements is even
if (i == m) {
rightMin = nums2[j];
} else if (j == n) {
rightMin = nums1[i];
} else {
rightMin = Math.min(nums1[i], nums2[j]);
}
return (leftMax + rightMin) / 2.0; // Return double
}
@Before
public void setUp() {
m = new MedianOfTwoSortedArrays();
}
@Test
public void testExamples() {
int[] A = {1, 2, 3, 4, 5};
int[] B = {2, 4, 5, 6, 7};
Assert.assertTrue(4 == m.findMedianSortedArrays(A, B));
}
@After
public void tearDown() {
m = null;
}
}