My question is with reference to Method 2 of this link. Here two equal length sorted arrays are given and we have to find the median of the two arrays merged.
Median of two arrays in Java
class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int n1 = nums1.length;
int n2 = nums2.length;
double find =0;
ArrayList list = new ArrayList();
for(int i =0;i<n1;i++)
list.add(nums1[i]);
for(int j =0;j<n2;j++)
list.add(nums2[j]);
Collections.sort(list);
int n = list.size();
if(n%2 != 0)
{
find = (Integer)list.get(n/2);
}
else if(n%2==0){
find = (Integer)list.get(n/2-1)+(Integer)list.get(n/2);
find = find/2;
}
return find;
}
}
For variable length you just have to check the special cases when either of the array is having only 1 element in each level of recursion . If one of them such , don't divide further just pass it as it is till the other one also becomes of length 2. While giving final answer handle the case when one of them is having only 1 element.
//Median of two sorted arrays
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception {
int[] A = {1, 3, 11};
int[] B = {2, 4, 12, 14, 15};
System.out.println("Ans. "+findMedian(A, B));
//System.out.println(median(A));
}
private static int findMedian(int[] A, int[] B) {
System.out.println(Arrays.toString(A)+" --- "+ Arrays.toString(B));
int sA = A.length;
int sB = B.length;
if(sA <= 2 && sB <= 2) {
if(sA <= 1 && sA <= 1) {
return (A[0]+B[0])/2;
} else if(sA <= 1) {
return (max(A[0], B[0]) + min(A[0], B[1])) / 2;
} else if(sB <= 1) {
return (max(A[0], B[0]) + min(A[1], B[0]) ) / 2;
} else {
System.out.println("xxx");
return (max(A[0], B[0]) + min(A[1],B[1])) / 2;
}
}
int mA = median(A);
int mB = median(B);
if(mA == mB) {
return mA;
} else if(mA < mB) {
if(sA <= 2) {
return findMedian(A, Arrays.copyOfRange(B, 0, sB/2+1));
} else if(sB <= 2) {
return findMedian(Arrays.copyOfRange(A, sA/2, sA), B);
} else {
return findMedian(Arrays.copyOfRange(A, sA/2, sA)
,Arrays.copyOfRange(B, 0, sB/2+1));
}
} else {
if(sA <= 2) {
return findMedian(A, Arrays.copyOfRange(B, sB/2, sB));
} else if(sB <= 2) {
return findMedian(Arrays.copyOfRange(A, 0, sA/2+1),B);
} else {
return findMedian(Arrays.copyOfRange(A, 0, sA/2+1)
,Arrays.copyOfRange(B, sB/2, sB));
}
}
}
private static int median(int[] A) {
int size = A.length;
if(size == 0 ){
return 0;
} else if(size == 1) {
return A[0];
}
if(size%2 == 0 ) {
return (A[size/2 -1 ] + A[size/2 ])/2;
}else {
return A[size/2];
}
}
private static int max(int a, int b) {
return a > b ? a : b;
}
private static int min(int a, int b) {
return a < b ? a : b;
}
}
... how can they say that the median of the merged arrays would be the median of the merged arrays resulting after pruning the halves of the arrays i.e. the median of merge array of {1, 12, 15, 26, 38} and {2, 13, 17, 30, 45} would be the median of the merge array of {2,13,17} and {15, 26, 38}.
This is because of the inequality that you used to prune the halves and by the definition of the median. A median splits a set of ordered numbers in two halves.
You know that 15 <= 17
(the median of the first set is less or equal to the median of the second set) and therefore the median must be between those two values. Anything less than 15 is pruned and anything greater than 17 is pruned, because they cannot contain the median value (since they don't split the set in two halves). And then you apply the same steps to a narrower set now; after pruning you halved the size of your search.
I try to visualize it for that example. The respective medians are marked by a *, except at the base case where the * marks the numbers used for calculating the median in that example.
1 12 *15* 26 38 2 13 *17* 30 45
15 *26* 38 2 *13* 17
*15* 26 13 *17* <-- base case
16
There are other base cases, though just a few. If you take into account of all the base cases you can ensure the algorithm terminates and returns the correct median.
I assumed that the median is a calculated number which separates a set in two halves.
When the total set has an odd number of elements the median is an number of that set. But in case of evenness sometimes you find it calculated the way I showed in that example (but sometimes one chooses the smaller element if you have to ensure the median is from the set, in which case it would be the 15).
Let me help you visualize it. Lets say it is case 3, the same argument follows for the other case. That means we have identified the median is present in 1st half of ar1 or second half of ar2. Now the question is why is the median of these halves same as the median of the original arrays, right.
So visualize putting just these relevant halves together in sorted order and finding its median. Now put the other left over halves back into this picture, where would they go. The first half of ar2, all n/2 elements have to go to the top of this new median and second half of arr1 all n/2 elements will have to go below this median (the exact locations is unimportant for median). So that means it will still be a median as equal number of elements are added above and below it. So the median of the two new halves is same as the median of the original set.
To be still more precise, let's see why first half of ar2 (a leftover half) has to go above the new median. That is the case because when we put all the elements together m2 has to go above the new median(since m2 < m1) which means all the first half of ar2 also have to go above the new median. In other words if m is the new median of the 2 selected halves, m2 < m => all first half of ar2 < m. Similar argument for the lower half of ar1. This means the new median m will remain the median of the entire set.
Looking more closely at your algo., though the approach is correct there might be a slight error in the algo while taking care of odd and even cases so beware while implementing.
@jayadev :
I don't agree with your answer.
"The first half of ar2, all n/2 elements have to go to the top of this new median and second half of arr1 all n/2 elements will have to go below this median "
Consider this test case: a1 = {1,2,15,16,17} a2 = {4,5,10,18,20}
PHP Solution:
function Solve( $aArrayOne, $aArrayTwo )
{
// Base case
if( empty( $aArrayOne ) || empty( $aArrayTwo ) )
{
return false;
}
$iCountOne = count( $aArrayOne );
$iCountTwo = count( $aArrayTwo );
// Single value arrays base case
if( $iCountOne === 1 && $iCountOne === $iCountTwo )
{
return ( $aArrayOne[ 0 ] + $aArrayTwo[ 0 ] ) / 2;
}
$iTotalElements = $iCountOne + $iCountTwo;
$iHalfElements = floor( $iTotalElements / 2 );
$aPartial = [];
$n = 0;
// Append elements to new combined array until midway point
while( $n <= $iHalfElements )
{
// Compared both of the first elements to get the
// smallest one into the partial array
if( $aArrayOne[ 0 ] <= $aArrayTwo[ 0 ] )
{
$aPartial[] = array_shift( $aArrayOne );
}
else
{
$aPartial[] = array_shift( $aArrayTwo );
}
++$n;
}
// Check to see if we have an odd or an even array for final element math.
$bIsOddAndPrecise = $iTotalElements % 2;
$iMedian = ( $bIsOddAndPrecise )
? $aPartial[ $n - 1 ]
: ( $aPartial[ $n - 1 ] + $aPartial[ $n - 2 ] ) / 2;
return $iMedian;
}
Use cases tested:
// $aArrayOne = [1, 3, 4 ];
// $aArrayTwo = [1, 2, 3 ];
// EXPECTED 1,1,2,3,3,4 -> (2+3)/2 2.5
// $aArrayOne = [1, 3, 4, 7, 8, 11, 44, 55, 62];
// $aArrayTwo = [2, 4, 5, 7, 33, 56, 77];
// Expected: 1,2,3,4,4,5,7,7,8,11,33,44,55,56,62,77 -> (7+8)/2 7.5
// $aArrayOne = [1, 3, 4 ];
// $aArrayTwo = [ 100, 100];
// EXPECTED 1,3,4,100,100 -> 4
// $aArrayOne = [1,5,8,10];
// $aArrayTwo = [7,9,14,];
// EXPECTED 1,2,7,8,9,10,14 - > 8
// $aArrayOne = [1,5,8,10];
// $aArrayTwo = [7];
// EXPECTED 1,5,7,8,10 - > 7
// $aArrayOne = [1,5,10];
// $aArrayTwo = [50, 50];
// EXPECTED 1,5,10,50,50 - > 10
// $aArrayOne = [50, 50];
// $aArrayTwo = [1,5,10];
// EXPECTED 1,5,10,50,50 - > 10
// $aArrayOne = [1];
// $aArrayTwo = [1];
// EXPECTED-> 1
// $aArrayOne = [100, 100];
// $aArrayTwo = [100];
// EXPECTED -> 100