4. 寻找两个有序数组的中位数
https://leetcode-cn.com/problems/median-of-two-sorted-arrays/
解法一:暴力
两数组合并找中位数,时间复杂度不符合要求。
解法二:二分
将A,B分成两部分,各自以i,j为界:
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
若能满足前提:
len(left_part) = len(right_part)
max(left_part) ≤ min(right_part)
则中位数容易求得:
median = (max(left_part) + min(right_part)) / 2
思路:每次在A中取中点i,根据前提约束求j = (m+n+1)//2 - i
,然后比较i,j所指元素的大小关系,调整区间。
主要根据这个结论,分三种情况:

解释一下第一种情况,为何j=0,i=m和B[j-1]<=A[i]
是等效的:
j=0,说明B的left部分为空,即B的right部分均大于A的left,(加上A的right本来就大于A的left)因此必然max(left_part) ≤ min(right_part)
;
i=m,说明A的right为空,即A的left均小于B的right,因此必然max(left_part) ≤ min(right_part)
;
B[j-1]<=A[i],这个不用解释了,即B的left中最大<=A的right中最小,必然max(left_part) ≤ min(right_part)
;
同理,i=0,j=n和A[i-1]<=B[j]
也是这样分析。
这两个条件必须同时满足。
此外为何j = (m+n+1)//2 - i
?
因为分析中要将A,B划分成相等的两段 此时i+j=m-i+n-j
, 即j=(m+n)//2-i
然而左右两段不一定相等(当m+n为奇数时):i+j=m-i+n-j+1
,即j=(m+n+1)//2-i
由于j是int类型,因此即使m+n是偶数,+1再除以2依然是原来的结果,就可以将m+n的奇数和偶数两种情况统一起来:
j = (m+n+1)//2 - i
class Solution:
def findMedianSortedArrays(self, A: List[int], B: List[int]) -> float:
m, n = len(A), len(B)
#有一个数组为空,直接求另一个的中位数
if m == 0:
return B[n//2]if n%2 == 1 else (B[n//2] + B[n//2-1]) / 2
if n == 0:
return A[m//2]if m%2 == 1 else (A[m//2] + A[m//2-1]) / 2
if m > n: #保证m<=n,用交换
A, B, m, n = B, A, n, m
iMin, iMax = 0, m
while iMin <= iMax: #在[iMin, iMax]之间搜索
i = (iMin + iMax) // 2 #i取中点
j = (m+n+1)//2 - i #前提约束求j
if j > 0 and i < m and B[j-1] > A[i]: #情况2
iMax += 1
elif i > 0 and j < n and A[i-1] > B[j]: #情况3
iMin -= 1
else: #情况1
if i == 0: leftMax = B[j-1]
elif j == 0: leftMax = A[i-1]
else: leftMax = max(A[i-1], B[j-1])
#若总长度为奇,则leftMax就是中位数
if (m+n)%2 == 1:
return leftMax
if i == m: rightMin = B[j]
elif j == n: rightMin = A[i]
else: rightMin = min(A[i], B[j])
#若总长度为偶,用公式计算中位数
return (leftMax + rightMin) / 2
最后更新于