问题
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.
Algorithm:
1) Calculate the medians m1 and m2 of the input arrays ar1[]
and ar2[] respectively.
2) If m1 and m2 both are equal then we are done.
return m1 (or m2)
3) If m1 is greater than m2, then median is present in one
of the below two subarrays.
a) From first element of ar1 to m1 (ar1[0...|_n/2_|])
b) From m2 to last element of ar2 (ar2[|_n/2_|...n-1])
4) If m2 is greater than m1, then median is present in one
of the below two subarrays.
a) From m1 to last element of ar1 (ar1[|_n/2_|...n-1])
b) From first element of ar2 to m2 (ar2[0...|_n/2_|])
5) Repeat the above process until size of both the subarrays
becomes 2.
6) If size of the two arrays is 2 then use below formula to get
the median.
Median = (max(ar1[0], ar2[0]) + min(ar1[1], ar2[1]))/2
Example:
ar1[] = {1, 12, 15, 26, 38}
ar2[] = {2, 13, 17, 30, 45}
For above two arrays m1 = 15 and m2 = 17
For the above ar1[] and ar2[], m1 is smaller than m2. So median is present in one of the following two subarrays.
[15, 26, 38] and [2, 13, 17]
Let us repeat the process for above two subarrays:
m1 = 26 m2 = 13.
m1 is greater than m2. So the subarrays become
[15, 26] and [13, 17]
Now size is 2, so median = (max(ar1[0], ar2[0]) + min(ar1[1], ar2[1]))/2
= (max(15, 13) + min(26, 17))/2
= (15 + 17)/2
= 16
I understand how they exclude halves of the arrays and say that the median element would be in particular halves of the arrays i.e. steps 1, 2, 3, 4, 5.
But what I can't fathom, 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}.
Please explain. Thanks in advance.
回答1:
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.
回答2:
... 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).
回答3:
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;
}
}
回答4:
Because of the equal length constraint, when we compare the two medians, we can safely discard values.
If m2 is larger than m1, we know that array two must contain a larger quantity of larger values than array one, and therefore all of the small values below m1 are not interesting as long as we discard an equal number of large values from array 2. The result will be a shorter array but the median we are looking for hasn't changed since we've trimmed equally from both sides.
It sort of reminds me of finding the center of mass of an object by supporting it with your hands far apart and then bringing them slowly together, keeping the object balanced.
回答5:
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
回答6:
This is my C# solution:
public double FindMedianSortedArrays(int[] nums1, int[] nums2) {
List<int> sorted = new List<int>();
if(nums1.Length>nums2.Length){
for(int i=0; i<nums1.Length; i++){
sorted.Add(nums1[i]);
if(i<nums2.Length)
sorted.Add(nums2[i]);
}
}
else{
for(int i=0; i<nums2.Length; i++){
sorted.Add(nums2[i]);
if(i<nums1.Length)
sorted.Add(nums1[i]);
}
}
sorted.Sort();
if(sorted.Count % 2 !=0)
return (double)sorted[sorted.Count/2];
return (double)(sorted[sorted.Count/2-1]+ sorted[sorted.Count/2])/2;
}
回答7:
Javascript solution to finding median of two sorted arrays:
const findMedian = (arr1, arr2) => {
const len = arr1.length + arr2.length;
return len % 2 ? oddMedian(Math.floor(len/2), arr1, arr2) : evenMedian((len/2)-1, len/2, arr1, arr2);
}
const oddMedian = (medianIndex, arr1, arr2) => {
if (arr1[arr1.length-1] < arr2[0]) {
if (arr1.length > medianIndex) {
return arr1[medianIndex];
} else if (arr1.length <= medianIndex) {
return arr2[medianIndex - arr1.length];
}
} else if (arr2[arr2.length-1] < arr1[0]) {
if (arr2.length > medianIndex) {
return arr2[medianIndex];
} else if (arr2.length <= medianIndex) {
return arr1[medianIndex - arr2.length];
}
} else {
const [shorterArr, largerArr] = arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
let j = 0;
let k = 0;
const sortedArr = [];
for (let i = 0; i <= medianIndex; i++) {
if (shorterArr[j] <= largerArr[k]) {
sortedArr[i] = shorterArr[j];
j++;
} else {
sortedArr[i] = largerArr[k];
k++;
}
}
return sortedArr[medianIndex];
}
}
const evenMedian = (medianIndex1, medianIndex2, arr1, arr2) => {
if (arr1[arr1.length-1] < arr2[0]) {
if (arr1.length-1 >= medianIndex2) {
return (arr1[medianIndex1]+arr1[medianIndex2])/2;
} else if (arr1.length-1 < medianIndex1) {
const firstMedianIndex = medianIndex1 - arr1.length;
return (arr2[firstMedianIndex]+arr2[firstMedianIndex+1])/2;
} else {
return (arr1[arr1.length-1] + arr2[0])/2;
}
} else if (arr2[arr2.length-1] < arr1[0]) {
if (arr2.length-1 >= medianIndex2) {
return (arr2[medianIndex1]+arr2[medianIndex2])/2;
} else if (arr2.length-1 < medianIndex1) {
const firstMedianIndex = medianIndex1 - arr2.length;
return (arr1[firstMedianIndex]+arr1[firstMedianIndex+1])/2;
} else {
return (arr2[arr2.length-1] + arr1[0])/2;
}
} else {
const [shorterArr, largerArr] = arr1.length < arr2.length ? [arr1, arr2] : [arr2, arr1];
let i = 0;
let j = 0;
let k = 0;
const sortedArr = [];
for (let i = 0; i <= medianIndex2; i++) {
if (shorterArr[j] <= largerArr[k]) {
sortedArr.push(shorterArr[j]);
j++;
} else {
sortedArr.push(largerArr[k]);
k++;
}
}
return (sortedArr[medianIndex1] + sortedArr[medianIndex2])/2;
}
}
Example
console.log("Result:", findMedian([1,3,5], [2,4,6,8]));
console.log("Result:", findMedian([1,3,5,7,10], [2,4,6,8]));
console.log("Result:", findMedian([1,3,5,7,10], [2,4,6,8,9]));
console.log("Result:", findMedian([1,3,5], [2,4,6,8,9]));
console.log("Result:", findMedian([1,3,5,7], [2,4,6,8,9,10]));
console.log("Result:", findMedian([1,3,5,7,10], [2,4,6]));
console.log("Result:", findMedian([1,3,5,7], [2,4]));
console.log("Result:", findMedian([1,2,4], [3,5,6,7,8,9,10,11]));
console.log("Result:", findMedian([1], [2, 3, 4]));
console.log("Result:", findMedian([1, 2], [3, 4]));
console.log("Result:", findMedian([1], [2, 3]));
Output
Result: 4
Result: 5
Result: 5.5
Result: 4.5
Result: 5.5
Result: 4.5
Result: 3.5
Result: 6
Result: 2.5
Result: 2.5
Result: 2
回答8:
@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}
回答9:
Here is a very simple solution.
Actually it need to merger two sorted array and then find the middle.
import java.util.Arrays;
public class MedianofTwoArray {
/**
* @param args
*/
public static void main(String[] args) {
int []array1= {1,2,3,4,5};
int []array2= {6,7,8,9,10};
int median;
median=findMedian(array1,array2);
System.out.println(median);
}
public static int findMedian(int []arr1,int []arr2) {
int [] tempArr=new int[arr1.length+arr2.length]; //creating an array of the length ,equals to sum of arr1 and arr2
int i=0;
int j=0;
int k=0;
while(i<arr1.length&&j<arr2.length) { /*comparing elements of the two arrays and copying the smaller one into tempArr and
incrementing the index of the array from which value is copied */
if(arr1[i]<=arr2[j]) {
tempArr[k]=arr1[i];
i++;
}else {
tempArr[k]=arr2[j];
j++;
}
k++;
}
//copying the left over elements from both arrays
if(i==arr1.length) {
while(j<arr2.length) {
tempArr[k]=arr2[j];
j++;
k++;
}
}else {
while(i<arr1.length) {
tempArr[k]=arr2[j];
j++;
k++;
}
}
System.out.println(Arrays.toString(tempArr));
return tempArr[tempArr.length/2];
}
}
来源:https://stackoverflow.com/questions/18790467/median-of-two-sorted-arrays