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

521 阅读2分钟

题目描述

给定两个大小分别为 m 和 n 的正序(从小到大)数组 nums1 和 nums2。请你找出并返回这两个正序数组的 中位数 。

算法的时间复杂度应该为 O(log (m+n)) 。

示例 1:

输入:nums1 = [1,3], nums2 = [2]
输出:2.00000
解释:合并数组 = [1,2,3] ,中位数 2
示例 2:

输入:nums1 = [1,2], nums2 = [3,4]
输出:2.50000
解释:合并数组 = [1,2,3,4] ,中位数 (2 + 3) / 2 = 2.5
示例 3:

输入:nums1 = [0,0], nums2 = [0,0]
输出:0.00000

解题思路1: 二分法

在上一篇中, 我们使用遍历2个数组的方法Accepted了这个题目, 但是时间复杂度不满足要求.
遍历法中, 我们通过每次遍历, 可以排除当前不符合要求的元素, 那么我们可以通过二分法, 每次遍历, 排除N个不符合要求的元素, 这样时间复杂度就会变低

  1. 假设2个数组元素总个数为N, 中位数的位置 K = (N+1)/2 (先只考虑奇数情况), 那么我们直接大胆的分别对2个数组的第 Q = K/2 个元素比较, 舍弃较小数对应数组的前 Q 个元素 [这里可以仔细思考一下为什么]
  2. 根据步骤1, 我们剩下需要舍弃的元素就是 K = K - Q个, 然后对2个新数组重复步骤1, 直到 K <= 1, 那么2个数组的第一个元素哪个小, 中位数就是哪个元素
  3. 为了兼容偶数情况, 我们直接去一次 K = (N+1)/2, 和 K = (N+2)/2 两种情况, 将结果相加除2就可以得到最终结果(奇数情况得到的2个结果相同)

图文演示

  • 步骤1

image.png

  • 步骤2

image.png

  • 步骤3

image.png

  • 步骤4

image.png

示例代码

def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float:
    def check(list1: List[int], list2: List[int], k: int) -> int:
        # 为了方便处理, 我们默认将list1作为比较短的数组处理
        if len(list1) > len(list2): 
            list1, list2 = list2, list1

        if len(list1) == 0:
            return list2[k-1]

        if k <= 1:
            return list1[0] if list1[0] < list2[0] else list2[0]

        tempK1 = min(len(list1), k // 2)
        tempK2 = min(len(list2), k // 2)
        t1, t2 = list1[tempK1 - 1], list2[tempK2 - 1]
        if t1 < t2:
            return check(list1[tempK1:], list2, k - tempK1)
        else:
            return check(list1, list2[tempK2:], k - tempK2)


    k1 = (len(nums1) + len(nums2) + 1) // 2
    k2 = (len(nums1) + len(nums2) + 2) // 2

    left = check(nums1, nums2, k1)
    right = check(nums1, nums2, k2)
    return (left + right) / 2