4. Median of Two Sorted Arrays

2020-01-26  本文已影响0人  oneoverzero

中位数的定义:如果某个有序数组长度是奇数,那么中位数就是最中间的那个数;如果是偶数,那么中位数就是最中间两个数字的平均值。

拓展到两个有序数组的中位数:假设两个有序数组的长度分别为m和n,由于两个数组长度之和m+n的奇偶性不定,因此需要分情况来讨论。对于奇数的情况,直接找到最中间的数即可,偶数的话需要求最中间两个数的平均值。

解这道题的关键并不是高超的算法,而是心中要有一副这样的图:
(参考:https://juejin.im/post/5c8c9ec16fb9a049af6e2a0d

              left side       |  right side 
nums1:   A(0),A(1),...,A(i-1) | A(i),...,A(m-1)
nums2:   B(0),B(1),...,B(j-1) | B(j),...,B(n-1)

我们把两个数组看成一个整体,有一根竖线将其中的元素从中间分开,且左边的部分和右边部分的元素相同(总数为奇数情况下,左边比右边多 1 个元素),那么当 m+n 为偶数时,中位数为
\frac{\max[A(i-1), B(j-1)] + \min[A(i), B(j)]}{2}
m+n 为奇数时,中位数为
\max[A(i-1), B(j-1)]
我们都知道,左边的元素为 i+j 个,而左右两边元素相同,则
i+j = \frac{m+n+1}{2}
我们可以用 i 来表示 j ,则
j = \frac{m+n+1}{2}-i
所以,该题就变成了,在数组 A 中寻找一个 i ,使得 A(i) \ge B(j-1) ,且 A(i-1) \le B(j) 成立,这两个不等式的含义是,竖线右边最小的数一定不比左边最大的数小,满足该条件,我们就可以说找到了这个竖线。

我们在找 i 的过程中,难免会碰到 A(i) < B(j-1) 的时候,此时我们需要将 i 向右移,使 A(i) 增大,当 i 右移,i 增大的同时,j 会减少,即 B(j-1) 的值会变小,这样操作 i 之后,会让我们更接近目标;同理,当 B(j) < A(i-1) 时,我们需要将 i 向左移。

通过上面的分析,我们最终可以使用二分查找法来寻找这个 i 值,又由于二分查找的时间复杂度为 O(\log n) ,这种方法可以满足题目的要求。

代码:(参考: https://leetcode.com/problems/median-of-two-sorted-arrays/discuss/2567/Python-O(log(min(mn))-solution

class Solution(object):
    def findMedianSortedArrays(self, nums1, nums2):
        """
        :type nums1: List[int]
        :type nums2: List[int]
        :rtype: float
        """
        length = len(nums1) + len(nums2)
        return self.findKth(nums1, nums2, length//2) if length%2==1 else \
              (self.findKth(nums1, nums2, length//2-1)+self.findKth(nums1, nums2, length//2))/2.0
    
    def findKth(self, A, B, k):
        if len(A) > len(B):
            A, B = B, A
        if not A:
            return B[k]
        if k == len(A) + len(B) - 1:
            return max(A[-1], B[-1])
        i = len(A) // 2
        j = k - i
        if A[i] > B[j]:
            return self.findKth(A[:i], B[j:], i)
        else:
            return self.findKth(A[i:], B[:j], j)

这里要注意的是,在C++中切片操作如 A[i:] 的时间复杂度是 O(1) ,但是在Python中这样做的时间复杂度是 O(n) 。因此上述代码的时间复杂度应为 O(n \log (\min (m, n)))

上一篇下一篇

猜你喜欢

热点阅读