4. 寻找两个有序数组的中位数

题目

  1. 中文题目

    中文题目

  2. 英文题目

    英文题目

分析

  1. 先要确定中位数是第几个数,两个数组中数一共有n个,则中位数为第 (frac{n+1}{2}) (n为奇数),第 (frac{n+1}{2})(frac{n+1}{2}+1) 的平均数个(n为偶数). 所以我们先找出第 (frac{n+1}{2}) 个数就很容易求出中位数了;
  2. 找中位数我们只需将数组分成两部分, 一侧的每一个数都比另一侧大. 且有一侧的个数刚好是(frac{n+1}{2}), 中位数就在我们分割的切口处;
  3. 时间复杂度要求为O(log(m+n)), 所以我们在找分割处时要使用二分法;
  4. 分割有多钟情况, 且需要注意极限情况;

正确代码

错误代码

1. 没有使用二分法导致时间复杂度很高且超出数组边界

class Solution {
    public double findMedianSortedArrays(int[] nums1, int[] nums2) {
       int medianFirst = (nums1.length + nums2.length + 1)/2;
        int aLeft = (nums1.length)/2 - 1;
        int bLeft = medianFirst - aLeft - 2;
        double median1;
        while(true){
            if(nums1[aLeft] > nums2[bLeft+1]){
                aLeft--;
                bLeft++;
            }else if (nums2[bLeft] > nums1[aLeft+1]){
                aLeft++;
                bLeft--;
            }else break;
        }
        median1 = Math.max(nums1[aLeft], nums2[bLeft]);
        if((nums1.length+nums2.length)%2!=0)
            return median1;
        else {
            return (median1 + Math.min(nums1[aLeft + 1], nums2[bLeft + 1])) / 2;
        }
    }  
}

测试用例为[1, 3], [2]

正确代码

class Solution {
    public static void main(String[] args) {
        int[] nums1 = {3};
        int[] nums2 = {-2, -1};

        double result = findMedianSortedArrays(nums1, nums2);
        System.out.println(result);
    }
    public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        //确保第一个数组长度更短
        if(nums1.length > nums2.length){
            return findMedianSortedArrays(nums2, nums1);
        }
        int length1 = nums1.length;
        int length2 = nums2.length;
        int totleLength = length1 + length2;
        //第一个中位数是排在第几的数
        int firstMI = (totleLength + 1) / 2;
        //二分法
        int left = 0;
        int right = length1;
        int line1;
        int line2;
        int left1;
        int right1;
        int left2;
        int right2;
        while(true){
            //第一个数组划分区域右边
            line1 = (left + right)/2;
            //第二个数组划分区域右边
            line2 = firstMI-line1;
            //检查数组越界的问题
            //第一个数组的左数
            left1 = line1 <=0 ? Integer.MIN_VALUE : nums1[line1-1];
            //第一个数组的右数
            right1 = line1 >= length1 ? Integer.MAX_VALUE : nums1[line1];
            //第二个数组的左数
            left2 = line2 <=0 ? Integer.MIN_VALUE : nums2[line2-1];
            //第一个数组的右数
            right2 = line2 >= length2 ? Integer.MAX_VALUE : nums2[line2];
            if(right1 < left2){
                //往右取值
                left = line1+1;            
            }else if(left1 > right2){
                //往左取值
                right = line1-1;
            }else{
                break;
            }
        }
        //第一个中位数
        int firstM = Math.max(left1, left2);
        //中位数
        double m = totleLength%2 == 0 ? ( firstM+Math.min(right1, right2) )/2.0 : firstM;
        return m;
    }
}
原文地址:https://www.cnblogs.com/karlshuyuan/p/14633561.html