两个排序数组的中位数:终止条件失败

时间:2015-07-27 09:08:06

标签: java arrays algorithm sorting median

下面的代码我是按照Median of two sorted arrays (method - 2)

的逻辑编写的

您甚至可以在Ideone.com

看到代码
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);
        }
    }
}

它不适用于像

这样的输入数组
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};

根据我的分析,问题是终止条件。一些来自geeksforgeeks的逻辑似乎与终止条件有关。

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

但是我无法解决它并使其适用于上述输入。 有人可以调查这个问题,让我知道我在哪里弄错了吗?

2 个答案:

答案 0 :(得分:3)

您的主要错误是当您执行int mid1 = (low1 + high1)/2; mid1时,mid1总是向左移动,然后您分配2n而不考虑此转换,因此每个嵌套比较比较从预期位置向左移位的数组元素,并且由于长度为a[n-1]+a[n]/2的数组的中位数始终为 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); ,因此在第一次执行比较后,您将比较数组的错误元素。你似乎无法实现方法2的代码块:

assert (high2-low2==high1-low1)

实际上,findMedian()入口处的简单low1_t会提醒您逻辑错误,因为对于大小为4的数组,第二个入口会产生不相等的数组大小。退出条件非常好,因为它直接从方法2的代码中复制。因此,您需要将分配 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); 和其他的块更改为以下内容:

median

并添加功能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; } ,如下所示:

{{1}}

完整示例(根据需要更改数组):http://ideone.com/zY30Vg

答案 1 :(得分:0)

这是一个有效的代码,它可以解决您的问题: -

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's middle count
  int bMid = k - aMid - 1; // b's 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);
 }