总览
本题目要求以对数级别的时间复杂度求得两个“有序”数组“共同”的中位数。虽然在时间复杂度上看似有十分严格的要求,但在掌握了题目的核心要点之后,您会发现本题实际上并不困难。
方法一 数组合并
直接将两个数组合并成一个数组,并取其中位数是最直观能想到的办法,但是显而易见的是这个方法的时间复杂度肯定是多项式级别。若两个数组的长度分别是$m$、$n$,那么将这两个数组合并须遍历一遍合并之后得到的数组,即时间复杂度为
$$
O(m+n)
$$
显然,这并不是满足题目要求的算法。(然而我做的时候这个算法居然通过了,速度还和二分查找方法一致)
方法二 二分查找
如果您想到一些目标是$O(logn)$的优化方法,例如二分法、二叉树等,但是并不知道该如何应用到本题上的话,可能是您对中位数的理解还不够透彻。在本题中,要从两个数组中找到中位数,可以考虑如下思路,
- 将数组重新组合成长度相等或长度相差不超过1;
- 两个数组必须满足某一个的最大值不大于另一个的最小值。
对于两个长度分别为$m$和$n$的有序数组$X$、$Y$,一定存在下标$i$,$j$,使得$X[0:i]$与$Y[0:j]$组成的数组$L$和$X[i:m]$与$Y[i:n]$组成的数组$R$满足上述两个条件,并且$i$与$j$满足如下关系,
$$
i + j = m - i + n - j
$$
即
$$
j = \frac{m + n - 2i}{2}
$$
同时,考察$Left$的最后一个值和$Right$的第一个值,即可得到中位数。换言之,只要求得$i$,本题得解。
问题已经转化为求分割数组$X$的那个下标,这时很自然的就可以想到使用复杂度为$O(logn)$二分查找,对于有序数组$X$,设正确分割的下标为$i_0$,对于下标$i$,得到$L$,$R$,则有
$$
L[i] > R[0] \wedge L[i] = X[i] \Rightarrow i > i_0 \
L[i] > R[0] \wedge L[i] = Y[j] \Rightarrow i < i_0 \
L[i] <= R[0] \Rightarrow i = i_0
$$
通过上述条件,可以判断真实值是在当前值的前边还是后边,满足二分查找的条件,可用二分查找得到$i_0$。
特别的,原数组为空时要做特殊处理。
这个方法的时间复杂度与二分查找的时间复杂度相同,本质上说,本题是一个二分查找的题目。
附录
Submission Detail by Myself(倒是花了很多时间在边界和特殊情况处理上)