1.将nums1,nums2所有的数分到两个组(group1, group2)内,保证第一个组的所有元素<=第二个组,且第一个组的元素个数为num1 + nums2元素众数整除2(total//2),如果找到这样的分组,则分奇偶讨论。1)总元素个数为偶数时,中位数为(max(group1), min(group2))/2。2)总元素个数为奇数时,中位数为min(group2)。
2.如果确定了nums1被分到第一组的元素个数(count_1),那么通过total//2-count_1也能确定nums2被分到第一组的元素个数。
假设在nums1数组index=i后切移到,在nums2数组index=j后切一刀,如:
{ nums1[0], nums1[1], ... nums1[i] }∈group1,{nums1[i+1], nums1[i+2], ...nums1[-1]}∈group2
{ nums2[0], nums2[1], ... nums2[j] }∈group1,{nums2[j+1], nums2[j+2], ...nums2[-1]}∈group2
其中group1中元素数量为total//2,即满足(i+1) + (j+1) = total // 2
Case1. 如果满足nums1[i] <= nums2[j+1] 且 nums2[j] <= nums1[i+1],则说明满足了group1中的元素全部小于group2中的元素。此时分组完成,可以通过1中的方法直接找到中位数。
Case2. 如果nums1[i] < nums2[j+1],说明nums1分入group1的元素偏少了,nums1切的位置应该在{nums1[i+1], nums1[i+2], ...nums1[-1]}中
Case3.如果nums2[j] < nums1[i+1],说明nums1分入group1的元素偏多了,nums1切的位置应该在{ nums1[0], nums1[1], ... nums1[i] }中
3.以上过程可以通过二分搜索的方式查找nums1数组在何处切了一刀
class Solution(object):
def getMedian(self, nums):
if len(nums) % 2 == 1:
return nums[len(nums) // 2]
else:
return (nums[len(nums) // 2] + nums[len(nums) // 2 - 1]) / 2.0
def findMedianSortedArrays(self, nums1, nums2):
"""
:type nums1: List[int]
:type nums2: List[int]
:rtype: float
"""
if not nums1:
return self.getMedian(nums2)
if not nums2:
return self.getMedian(nums1)
# 保证左边的元素 <= 右边的元素
total = len(nums1) + len(nums2)
left_half = total // 2
head = 0
tail = len(nums1)
while True:
# 左边包含了nums1[0]...nums1[cut1]
# 以及 nums2[0]...nums2[cut2]
if tail == 0:
cut1 = -1
break
cut1 = (head + tail) // 2
cut2 = left_half - (cut1 + 1) - 1
# case1: 左半部分包含的nums1元素超过了总体半数,cut1应当向左移
if cut2 < -1:
tail = cut1
# case2: 左半部分包含的nums1元素过少,导致nums2全部放入左半部分也不够,cut1应当向右移
elif cut2 >= len(nums2):
head = cut1 + 1
else:
# case 3:nums1[cut1] > nums2[cut2 + 1],cut1应当向左移
if cut1 >= 0 and cut2 + 1 < len(nums2) and nums1[cut1] > nums2[cut2 + 1]:
tail = cut1
# case 4:nums2[cut2] > nums1[cut1 + 1],cut1应当向右移
elif cut2 >= 0 and cut1 + 1 < len(nums1) and nums2[cut2] > nums1[cut1 + 1]:
head = cut1 + 1
else:
# case 5
# 找到合理的划分
break
cut2 = left_half - (cut1 + 1) - 1
max_num = max(nums1[-1], nums2[-1])
min_num = min(nums1[0], nums2[0])
a1 = min_num if cut1 < 0 else nums1[cut1]
b1 = min_num if cut2 < 0 else nums2[cut2]
a2 = max_num if cut1 + 1 >= len(nums1) else nums1[cut1 + 1]
b2 = max_num if cut2 + 1 >= len(nums2) else nums2[cut2 + 1]
if total % 2 == 1:
return min(a2, b2)
else:
return (max(a1, b1) + min(a2, b2)) / 2.0