题目描述
给定两个大小分别为 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个不符合要求的元素, 这样时间复杂度就会变低
- 假设2个数组元素总个数为N, 中位数的位置 K = (N+1)/2 (先只考虑奇数情况), 那么我们直接大胆的分别对2个数组的第 Q = K/2 个元素比较, 舍弃较小数对应数组的前 Q 个元素 [这里可以仔细思考一下为什么]
- 根据步骤1, 我们剩下需要舍弃的元素就是 K = K - Q个, 然后对2个新数组重复步骤1, 直到 K <= 1, 那么2个数组的第一个元素哪个小, 中位数就是哪个元素
- 为了兼容偶数情况, 我们直接去一次 K = (N+1)/2, 和 K = (N+2)/2 两种情况, 将结果相加除2就可以得到最终结果(奇数情况得到的2个结果相同)
图文演示
- 步骤1
- 步骤2
- 步骤3
- 步骤4
示例代码
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