算法总结之 在两个长度相等的排序数组中找到上中位数

题目描述: arr1  和 arr2   长度都为N   求两个数组中所有数的上中位数

要求 时间复杂度 O(logN)  额外空间复杂度O(1)

 

这道题目的方法比较好玩:

   这两个数组如下表示:

 arr1[start1....end1]     arr2[start2...end2]

如果start1==start2  那么也有start2==end2   此时元素总个数是2个,上中位数为最小的那个  

如果start1!=start2  令mid1={start1+end1}/2      mid1={start2+end2}/2

     进而分情况

                             情况一、 如果arr1[mid1] == arr2[mid2]

                                                    如果两个数组长度为奇数或者偶数,那么arr1[mid1] == arr2[mid2]=上中位数

                             情况二、如果arr1[mid1] >arr2[mid2]

                                                   如果长度为奇数、(假设为5)arr1的第三个数>arr2的第三个数  此时上中位数只能是从arr1的{1,2,3}和arr2的{3,4,5}的共同的上中位数找 

                                                   如果长度为偶数,(假设为4)arr1的第二个数>arr2的第二个数  此时上中位数只能是从arr1的{1,2}和arr2的{3,4}的共同的上中位数找 

                                          如果arr1[mid1] <arr2[mid2]情况完全一致  请读者自行推理

 

代码实现是这样:

  特别类似于二分查找 哈哈  也是找mid 然后通过min去比较

     其实两个数组长度是一致的  某种程度上说是当前数组的影子 或者 映射吧 都是有关联的 所以重点操作一个数组 然后通过某种关系去映射另外一个数组就OK了

    比较两个数组mid的值 决定两个数组 后面遍历的走向

 

废话不多说,上代码:

package TT;

public class Test12 {

    public  static int getUpMedian(int[] arr1 , int[] arr2){
        
        if(arr1==null || arr2==null || arr1.length != arr2.length){
            throw new RuntimeException("hi,babay.are you ok?");
        }
        
        int start1 =0;
        int end1 = arr1.length-1;
        
        int start2=0;
        int end2 = arr2.length-1;
        
        int mid1 =0;
        int mid2 =0;
        
        int offset = 0;

        while(start1 < end1){
            mid1 = (start1+end1)/2;
            mid2 = (start2+end2)/2;
            //元素个数如果是奇数为0 偶数为1
            offset = ((end1 - start1+1)&1)^1;
            if(arr1[mid1] > arr2[mid2]){
                end1 = mid1;
                start2=mid2+offset;
            }else if(arr1[mid1]<arr2[mid2]){
                start1 = mid1 + offset;
                end2 = mid2;
            
            }else {
                return arr1[mid1];
            }            
        }
        
        return Math.min(arr1[start1], arr2[start2]);   
    }
    
    public static void main(String[] args){
        
           int[] a1 = new int[4];
           int[] a2 = new int[4];
           
          a1[0]=0;  a1[1]=1;  a1[2]=2; a1[3]=3;
          a2[0]=4;  a2[1]=5;  a2[2]=5; a2[3]=6;

          int c = getUpMedian(a1,a2);
          
          System.out.println(c);
        
        
    }
     
}

结果:

 

手写实现很多思路,我觉得这样写是最清晰明了的

public class Test4 {
    public static int getMidValue(int[] arr1, int[] arr2) {
        // 参数验证
        if (arr1 == null || arr2 == null || arr1.length != arr2.length) {
            throw new RuntimeException("请检查参数");
        }
        // 执行业务逻辑 (左右指针)
        int start1 = 0;
        int end1 = arr1.length - 1;

        int start2 = 0;
        int end2 = arr2.length - 1;

        while (start1 < end1) {
            int mid1 = (end1 - start1) / 2;
            int mid2 = (end2 - start2) / 2;
            // 移动的开关 (元素个数奇数偶数判断取决于 移动与否)
            int offset = (end1-start1+1)%2  == 0 ? 1 : 0;    //时刻判断
            if (arr1[mid1] > arr2[mid2]) {
                end1 = mid1;
                start2 = mid2 + offset;
            } else if (arr1[mid1] < arr2[mid2]) {
                end2 = mid2;
                start1 = mid1 + offset;
            } // 如果相等的话就直接返回了
            return Math.min(arr1[start1], arr2[start1]);

        }

        return Math.min(arr1[start1], arr2[start1]);
    }

    public static void main(String[] args) {
        int[] arr1 = { 1, 3, 5, 7 };
        int[] arr2 = { 2, 4, 6, 8 };
        int midValue = getMidValue(arr1, arr2);
        System.out.println(midValue);
    }
}

 

posted @ 2017-08-23 10:56  toov5  阅读(753)  评论(0编辑  收藏  举报