题目:寻找两个有序数组的中位数
给定两个大小为 m 和 n 的有序数组 nums1
和 nums2
。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1
和 nums2
不会同时为空。
示例 1:
1 | nums1 = [1, 3] |
示例 2:
1 | nums1 = [1, 2] |
思路
这题目乍一看有点绕,其实简单一点考虑就是找这两个数组集合的中位数。
- 先把两个数组合并成一个数组temp = nums1 + nums2
- 然后再对这个新数组进行排序
- 找中位数:
- 当这个数组长度是奇数时:中位数就是排在最中间的那个数
- 当这个数组长度是偶数时:中位数就是排在最中间的两个数的平均数
实现如下:
1 | class Solution: |
官方解答
这题的官方解答看起来比较复杂,但考虑到上面的解法用到了sort()
方法,可能本身就存在算法复杂度高的问题。所以官方解答使用了递归排序的方法。
先不考虑特殊情况,分别将两个数组划分成两部分
1
2
3left_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]那么如果left_part的长度等于right_part的长度,且right_part的值都大于left_part的值(即min(right_part)>=max(left_part))。我们就找到了中位数:
$median=\frac{max(left_part)+min(right_part)}{2}$
那么i和j有什么关系呢?
当总长度$m+n$为偶数时:
两边长度相等:$i+j=m-i+n-j$ ,所以可以得到$j=\frac{m+n}{2}-i$。
当总长度$m+n$为奇数时:
左边比右边多1个数:$i+j=m-i+n-j+1$,所以得到:$j=\frac{m+n+1}{2}-i$。
由于$i, j$会不断移动,我们取较大值:$j=\frac{m+n+1}{2}-i$。
先不考虑临界情况,并假设$m<n$,我们需要在$[0,m]$中找到$i$可以使$B[j-1]<=A[i]$且$A[i-1]<=B[j]$。
现在我们可以开始按二叉树进行查找:
- 初始化i的查找范围$imin = 0$,$ imax = m$,$i=\frac{imin+imax}{2}$。并动态调整$imin,imax$的值,为了方便可以不需要考虑奇数偶数,通过
int()
取整即可,如果是奇数那么i与原值一样,会继续调整$imin,imax$的值,直到下一个 - 当$i<m, B[j-1]>A[i]$时,我们需要增加$imin = imin + 1$
- 当$i>0, A[i-1]>B[j]$时,我们需要减小$imax = imax -1$。
- 初始化i的查找范围$imin = 0$,$ imax = m$,$i=\frac{imin+imax}{2}$。并动态调整$imin,imax$的值,为了方便可以不需要考虑奇数偶数,通过
最终结果,要考虑下特殊情况:
左边最大值max_of_left:
- 当$i=0$时:$B[j-1]$
- 当$j=0$时:$A[i-1]$
max(a[i-1], B[j-1])
当总长度m+n为奇数时,直接返回左边最大值
右边最小值min_of_right:
- 当$i=m$时:$B[j]$
- 当$j=0$时:$A[i]$
Min(A[i], B[j])
当总长度为偶数时,返回(max_of_left + min_of_right)/ 2
实现如下:
1 | class Solution: |
还是有点绕,如果大家有更好的方法或者思路,欢迎一起探讨。