codeTop100题(40)4. 寻找两个正序数组的中位数

40 阅读2分钟

1. 题目

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

2. 分析

首先我们来看两个case:

1 2 3 4 5 6
1 4 6 8

length = 10
中位数= (4 + 4) / 2
中位数下标= 4( (n+m)/2 - 1 ) 、 5 ( (n+m)/2 )
1 2 3 4 5
1 4 6 8

length = 9
中位数= 4
中位数下标= 4 = (n+m)/2

转换一下思路,找中位数其实是找一个第 (n+m)/2 + 1 小的数;

例如这个case,其实我们使用两个指针,分别指向两个数组的下标0,每一次都比大小,然后小的移动一次; 1 2 3 4 5 5 1 4 6 8

最终需要移动(n+m)/2次;

但是,我们是否可以采取二分的思路; 设k = (n+m)/2 即(左边需要排除的数) ;每次在取mid = k/2,即在两个数组中各取mid个数,最后在索引的位置判断大小,小的数组就直接排除,这样子我们可以更快的移动指针到我们需要的中位数下标上。

边界条件: 如果数组越界了就直接使用数组的长度,最后k-剩余长度就好了 如果其中一个数组为空,那直接在另一个数组上取中位数就好了 当mid = 0的时候,就取长度1

3. 代码

public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
    //奇数
    if ((nums1.length + nums2.length) % 2 != 0) {
        return findMedianSortedArraysSub(nums1, nums2, 0, 0, (nums1.length + nums2.length) / 2);
    }
    //偶数
    return (findMedianSortedArraysSub(nums1, nums2, 0, 0, (nums1.length + nums2.length) / 2 - 1) +
            findMedianSortedArraysSub(nums1, nums2, 0, 0, (nums1.length + nums2.length) / 2)) / 2.0;
}

public static int findMedianSortedArraysSub(int[] nums1, int[] nums2, int s1, int s2, int k) {
    if (k == 0) {
        if (s1 >= nums1.length) {
            return nums2[s2];
        }
        if (s2 >= nums2.length) {
            return nums1[s1];
        }
        return Math.min(nums1[s1], nums2[s2]);
    }

    if (s1 == nums1.length) {
        return findMedianSortedArraysSub(nums1, nums2, s1, s2 + k, 0);
    }
    if (s2 == nums2.length) {
        return findMedianSortedArraysSub(nums1, nums2, s1 + k, s2, 0);
    }

    int mid = k / 2;
    mid = mid == 0 ? 1 : mid;

    if (s1 + mid - 1 >= nums1.length) {
        return nums1[nums1.length - 1] <= nums2[s2] ? findMedianSortedArraysSub(nums1, nums2, nums1.length, s2, k - nums1.length + s1) :
                findMedianSortedArraysSub(nums1, nums2, s1, s2 + mid, k - mid);
    }
    if (s2 + mid - 1 >= nums2.length) {
        return nums1[s1] <= nums2[nums2.length - 1] ? findMedianSortedArraysSub(nums1, nums2, s1 + mid, s2, k - mid) :
                findMedianSortedArraysSub(nums1, nums2, s1, nums2.length, k - nums2.length + s2);
    }

    return nums1[s1 + mid - 1] <= nums2[s2 + mid - 1] ? findMedianSortedArraysSub(nums1, nums2, s1 + mid, s2, k - mid) :
            findMedianSortedArraysSub(nums1, nums2, s1, s2 + mid, k - mid);
}