【004】Median of Two Sorted Arrays.md

【004】Median of Two Sorted Arrays

题目

There are two sorted arrays nums1 and nums2 of size m and n respectively.

Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).

You may assume nums1 and nums2 cannot be both empty.

Example 1:

nums1 = [1, 3]
nums2 = [2]

The median is 2.0

Example 2:

nums1 = [1, 2]
nums2 = [3, 4]

The median is (2 + 3)/2 = 2.5

词汇

respectively 分别
median 中位数
complexity 复杂度

翻译

求两个有序数组的中位数,并且限制了时间复杂度为O(log (m+n))

中位数的定义为把两个数组合并过后进行升序排序后,处于数组中间的那个数,此时如果合并后的数组元素个数为偶数,则为中间两个数的平均值。

解题思路

初看起来这就是个寻找第k小数的问题,解决方案有很多,最简单的就是采用归并排序的思想把两个数组进行合并,然后取中间的数就可以了。但问题在于,这个题目限定了时间复杂度为O(log(m+n)),而合并算法的时间复杂度为O(nlogn),显然不合题意。另外一个方法是设置一个双指针,一开始都指向两个数组的开头,不停地比较两个指针指向的元素的大小,指向小元素的指针的往前移一个元素去追指向大元素的指针,一直移动(len1+len2)/2次后就能得到中位数,但是这个算法的时间复杂度仍然不符合题意,为O(n)

但是注意到这个题目给定的数组已经是排过序的了,算法导论中对order statistic问题进行过讨论,因此,在有序又要求log级的时间复杂度,可以考虑分治策略,采用二分法。

大方向定好了,但是并不清楚具体要怎么去完成这个二分法,我们应该对什么去做二分?其实这个题目需要找的就是第k小的元素问题,假设我们的第k小的数是在第一个数组中找了p次,然后在第二个数组中找了q次,那么满足关系:p+q=k。进一步的,寻找第k小的数的过程就是寻找p和q的过程,k我们是知道的,但是p和q是不知道的,因此事实上我们的目标就是去搜索p(找到了p就等于找到了q),因此我们二分法的目标,事实上就是二分k来找p。

代码实现-Java

解法一
public static double findMedianSortedArrays(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length, left = (m + n + 1) / 2, right = (m + n + 2) / 2;
        return (findKth(nums1, nums2, left) + findKth(nums1, nums2, right)) / 2.0;
}

public static int findKth(int[] nums1, int[] nums2, int k) {
    int m = nums1.length, n = nums2.length;
    if (m > n) {
        return findKth(nums2, nums1, k);
    }
    if (m == 0) {
        return nums2[k - 1];
    }
    if (k == 1) {
        return Math.min(nums1[0], nums2[0]);
    }
    int i = Math.min(m, k / 2), j = Math.min(n, k / 2);
    if (nums1[i - 1] > nums2[j - 1]) {
        return findKth(nums1, Arrays.copyOfRange(nums2, j, n), k - j);
    } else {
        return findKth(Arrays.copyOfRange(nums1, i, m), nums2, k - i);
    }
}
解法二
public double findMedianSortedArrays_2(int[] nums1, int[] nums2) {
        int m = nums1.length, n = nums2.length;
        if (m < n) {
            return findMedianSortedArrays_2(nums2,nums1);
        }
        if (n == 0) {
            return (nums1[(m - 1) / 2] + nums1[m / 2]) / 2.0;
        }
        int left = 0, right = 2 * n;
        while (left <= right) {
            int mid2 = (left + right) / 2;
            int mid1 = m + n - mid2;
            double L1 = mid1 == 0 ? Double.MIN_VALUE : nums1[(mid1 - 1) / 2];
            double L2 = mid2 == 0 ? Double.MIN_VALUE : nums2[(mid2 - 1) / 2];
            double R1 = mid1 == m * 2 ? Double.MAX_VALUE : nums1[mid1 / 2];
            double R2 = mid2 == n * 2 ? Double.MAX_VALUE : nums2[mid2 / 2];
            if (L1 > R2) {
                left = mid2 + 1;
            } else if (L2 > R1) {
                right = mid2 - 1;
            } else {
                return (Math.max(L1, L2) + Math.min(R1, R2)) / 2;
            }
        }
        return -1;
    }

代码实现-Python

def median(A, B):
    m, n = len(A), len(B)
    if m > n:
        A, B, m, n = B, A, n, m
    if n == 0:
        raise ValueError

    imin, imax, half_len = 0, m, (m + n + 1) / 2
    while imin <= imax:
        i = (imin + imax) / 2
        j = half_len - i
        if i < m and B[j-1] > A[i]:
            # i is too small, must increase it
            imin = i + 1
        elif i > 0 and A[i-1] > B[j]:
            # i is too big, must decrease it
            imax = i - 1
        else:
            # i is perfect

            if i == 0: max_of_left = B[j-1]
            elif j == 0: max_of_left = A[i-1]
            else: max_of_left = max(A[i-1], B[j-1])

            if (m + n) % 2 == 1:
                return max_of_left

以上代码会同步更新在本人的Github和CSDN上

Github地址:https://github.com/Bylant/LeetCode

CSDN地址:https://blog.csdn.net/ZBylant
微信公众号 在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值