直接回答:对较短的数组做二分,寻找一种「划分」:把两个数组各切成左右两半,使左半部分的元素总数等于总数的一半,且左半所有元素 ≤ 右半所有元素。满足条件的划分下,中位数就是「左半最大值」与「右半最小值」的组合(奇数取左半最大,偶数取两者均值)。每轮二分排除短数组的一半,时间 O(log(min(m, n)))、空间 O(1)。

展开解析:设短数组 A 在 i 处切开、长数组 B 在 j = (m+n+1)//2 − i 处切开,正确划分需满足 A[i−1] <= B[j] 且 B[j−1] <= A[i];不满足时根据哪边违例收缩二分区间。边界用 ±∞ 哨兵处理切点在端点的情况,这是最容易写错的地方。思路本质是「第 K 小数」问题的特例:在两个有序数组中找第 k 小,每轮比较两数组第 k/2 个元素,排除较小者所在数组的前 k/2 个,k 减半递归——掌握这个通用版本后中位数只是 k = (m+n+1)/2 的代入。追问方向:为什么只对短数组二分(保证 j 非负)、偶数总长时左右两个中位数的取法、归并思路的 O(m+n) 解为什么不符合要求。

示例

def find_median(A, B):
    if len(A) > len(B):
        A, B = B, A
    m, n = len(A), len(B)
    half, lo, hi = (m + n + 1) // 2, 0, m
    while lo <= hi:
        i = (lo + hi) // 2
        j = half - i
        aL = A[i - 1] if i else float('-inf')
        aR = A[i] if i < m else float('inf')
        bL = B[j - 1] if j else float('-inf')
        bR = B[j] if j < n else float('inf')
        if aL <= bR and bL <= aR:
            left_max = max(aL, bL)
            if (m + n) % 2:
                return left_max
            return (left_max + min(aR, bR)) / 2
        if aL > bR:
            hi = i - 1
        else:
            lo = i + 1