leetcode题解-4. Median of Two Sorted Arrays

本题难度为hard,确实不容易做出来。之前做的时候时间复杂度最差应该是O(m+n),不符合题目要求,因此这次再刷的时候又反复看资料,选择了一个O(log(m+n))的方法。其实还有一个O(log(min(m,n)))的方法在官方的article中,但是不容易理解,并且不具有代表性,因此这里只介绍O(log(m+n))的算法。

该问题的核心是将原问题分解成一个寻找第k小数的问题(假设两个原序列升序排列),这样中位数实际上是第(m+n)/2小的数。所以只要解决了第k小数的问题,原问题也得以解决。

首先假设数组A和B的元素个数都大于k/2,我们比较A[k/2-1]和B[k/2-1]两个元素,这两个元素分别表示A的第k/2小的元素和B的第k/2小的元素。这两个元素比较共有两种情况:>和<。如果A[k/2-1] < B[k/2-1],这表示A[0]到A[k/2-1]的元素都在A和B合并之后的前k小的元素中。换句话说,A[k/2-1]不可能大于两数组合并之后的第k小值,所以我们可以将其抛弃。

当A[k/2-1]>B[k/2-1]时存在类似的结论。

通过上面的分析,我们即可以采用递归的方式实现寻找第k小的数。此外我们还需要考虑几个边界条件。如果我们以aStart 和bStart 来代表两个数组寻找第k小数的指针,那么:
如果aStart > A.length - 1,那么返回B[bStart + k - 1]
如果bStart > B.length - 1,那么返回A[aStart + k - 1]
如果k == 1, 代表已经找到了第K小的数了,那么就返回Math.min(A[aStart], B[bStart])
最终实现的代码为:

class Solution {
    public static double findMedianSortedArrays(int[] A, int[] B) {
        int m = A.length, n = B.length;
        int l = (m + n + 1) / 2;
        int r = (m + n + 2) / 2;
        return (find_k(A, 0, B, 0, l) + find_k(A, 0, B, 0, r)) / 2.0;
    }
    public static double find_k(int[] A, int aStart, int[] B, int bStart, int k) {
        if (aStart > A.length - 1) return B[bStart + k - 1];            
        if (bStart > B.length - 1) return A[aStart + k - 1];                
        if (k == 1) return Math.min(A[aStart], B[bStart]);

        int aMid = Integer.MAX_VALUE, bMid = Integer.MAX_VALUE;
        if (aStart + k/2 - 1 < A.length) aMid = A[aStart + k/2 - 1]; 
        if (bStart + k/2 - 1 < B.length) bMid = B[bStart + k/2 - 1];        

        if (aMid < bMid) 
            return find_k(A, aStart + k/2, B, bStart,       k - k/2);// Check: aRight + bLeft 
        else 
            return find_k(A, aStart,       B, bStart + k/2, k - k/2);// Check: bRight + aLeft
    }
    public static void main(String[] args) {
        int[] nums1 = {1,2,4,5,6};
        int[] nums2 = {3,7,8,9,10,11};
        System.out.println(findMedianSortedArrays(nums1, nums2));
    }
}

你可能感兴趣的:(Leetcode题解)