Median of two sorted arrays: termination condition

Below is the code I wrote following the logic of Median of two sorted arrays (method - 2)

You can even see the Ideone.com code

class MedianOfTwoArrays {
    public static void main(String[] args) {
        // Note: These are sorted arrays and are of equal length.
        int[] array1 = {1, 12, 15, 26, 38};
        int[] array2 = {2, 13, 17, 30, 45};

        int median = getMedianOfTwoArrays(array1, array2);
        System.out.println(median);
    }

    static int getMedianOfTwoArrays(int[] array1, int[] array2) {
        int index1 = array1.length/2;
        int index2 = array2.length/2;

        int m1 = array1[index1];
        int m2 = array2[index2];

        if(m1 == m2) {
            return m1;
        } else {
            return findMedian(array1, array2, 0, array1.length - 1, 0, array2.length - 1);
        }
    }


    static int findMedian(int[] array1, 
                            int[] array2, 
                                int low1, 
                                    int high1, 
                                        int low2, 
                                            int high2) {


        if((high1 - low1 + 1) == 2 && (high2 - low2 + 1) == 2) {
                return (Math.max(array1[low1], array2[low2]) + Math.min(array1[high1], array2[high2]))/2;
        }

        int mid1 = (low1 + high1)/2;
        int mid2 = (low2 + high2)/2;

        int m1 = array1[mid1];
        int m2 = array2[mid2];

        int low1_t = 0;
        int high1_t = 0;
        int low2_t = 0;
        int high2_t = 0;

        if(m1 == m2) {
            return m1;
        } else if(m1 > m2) {
            low1_t = low1;
            high1_t = mid1;
            low2_t = mid2;
            high2_t = high2;
            return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);
        } else {
            low1_t = mid1;
            high1_t = high1;
            low2_t = low2;
            high2_t = mid2;
            return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);
        }
    }
}

      

It doesn't work for arrays of input, like

int[] array1 = {1, 5, 17, 20}; // median is 10
int[] array2 = {4, 8, 13, 19};

int[] array1 = {1, 3, 5, 7, 9, 11}; // median is 6
int[] array2 = {2, 4, 6, 8, 10, 12};

      

The problem in my analysis is the termination condition. Some of what the logic suggested by geeksforgeeks seems to have some problem with the termination condition.

(Math.max(array1[low1], array2[low2]) + Math.min(array1[high1], array2[high2]))/2;

      

But I couldn't solve it and get it to work for the above inputs. Can someone please investigate this issue and let me know where I am doing the error?

+3


source to share


2 answers


The main mistake is that when idle, int mid1 = (low1 + high1)/2;

yours is mid1

always shifted to the left and then you assign mid1

without taking that shift into account, so each nested comparison compares the elements of the arrays that are shifted to the left of the intended position, and since the median of the length array is 2n

always a[n-1]+a[n]/2

, you are comparing the wrong elements arrays after the first comparison. You have seemingly implemented this block of method 2 code:

    if (n % 2 == 0)
        return getMedian(ar1 + n/2 - 1, ar2, n - n/2 +1);
    else
        return getMedian(ar1 + n/2, ar2, n - n/2);

      

In fact, a simple assert (high2-low2==high1-low1)

input to findMedian()

would warn you of the wrong logic, since with arrays of size 4, the second input gives unequal array sizes. The exit condition is pretty good as it is directly copied from the code of method 2. So you need to change the destination block low1_t

and others like this:

    assert (high2-low2==high1-low1); // sanity check
    int n=high1-low1+1; // "n" from logic

    int m1 = median(array1,low1,high1);
    int m2 = median(array2,low2,high2);

    int low1_t = low1;
    int high1_t = high1;
    int low2_t = low2;
    int high2_t = high2;

    if(m1 == m2) {
        return m1;
    } else if(m1 > m2) {
        if (n % 2 == 0) {
            high1_t = high1-n/2+1;
            low2_t = low2+n/2-1;
        } else {
            high1_t = high1-n/2;
            low2_t = low2+n/2;
        }
    } else {
        if (n % 2 == 0) {
            low1_t = low1+n/2-1;
            high2_t = high2-n/2+1;
        } else {
            low1_t = low1+n/2;
            high2_t = high2-n/2;
        }
    }
    return findMedian(array1, array2, low1_t, high1_t, low2_t, high2_t);

      



And add the function median

like this:

static int median(int[] arr, int low,int hig) 
{
    if ((low+hig)%2 == 0) return arr[(low+hig)/2];
    int mid=(low+hig)/2;
    return (arr[mid]+ arr[mid-1])/2;
}

      

Full example (change arrays if necessary): http://ideone.com/zY30Vg

+3


source


This is a working code and it should solve your problem: -



public static void main(String[] args)
 {
    int[] ar1 = {1, 3, 5, 7, 9, 11};
    int[] ar2 = {2, 4, 6, 8, 10, 12};
  System.out.println((int) findMedianSortedArrays(ar1,ar2));
 }

 public static double findMedianSortedArrays(int A[], int B[]) {
  int m = A.length;
  int n = B.length;

  if ((m + n) % 2 != 0) // odd
   return (double) findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1);
  else { // even
   return (findKth(A, B, (m + n) / 2, 0, m - 1, 0, n - 1) 
    + findKth(A, B, (m + n) / 2 - 1, 0, m - 1, 0, n - 1)) * 0.5;
  }
 }

 public static int findKth(int A[], int B[], int k, 
  int aStart, int aEnd, int bStart, int bEnd) {

  int aLen = aEnd - aStart + 1;
  int bLen = bEnd - bStart + 1;

  // Handle special cases
  if (aLen == 0)
   return B[bStart + k];
  if (bLen == 0)
   return A[aStart + k];
  if (k == 0)
   return A[aStart] < B[bStart] ? A[aStart] : B[bStart];

  int aMid = aLen * k / (aLen + bLen); // a middle count
  int bMid = k - aMid - 1; // b middle count

  // make aMid and bMid to be array index
  aMid = aMid + aStart;
  bMid = bMid + bStart;

  if (A[aMid] > B[bMid]) {
   k = k - (bMid - bStart + 1);
   aEnd = aMid;
   bStart = bMid + 1;
  } else {
   k = k - (aMid - aStart + 1);
   bEnd = bMid;
   aStart = aMid + 1;
  }

  return findKth(A, B, k, aStart, aEnd, bStart, bEnd);
 }

      

0


source







All Articles