题目描述
There are two sorted arrays nums1
and nums2
of size m
and n
respectively.
Find the median of the two sorted arrays. The overall run time complexity should be
O(log(m+n))
O
(
log
(
m
+
n
)
)
.
Example 1:
nums1 = [1, 3]
nums2 = [2]
The median is 2.0
Example 2:
nums1 = [1, 2]
nums2 = [3, 4]
The median is (2 + 3)/2 = 2.5
算法思路
本题是求两个有序数组的中位数,最简单的想法是用两个指针遍历数组,每次寻找两个数组的最小值,总遍历 (m+n)/2 ( m + n ) / 2 次后便可以找到中位数,时间复杂度为 O(m+n) O ( m + n ) 。
题目要求时间复杂度为 O(log(m+n)) O ( log ( m + n ) ) ,所以要思考更高效的算法。
首先思考中位数的本质,对于一系列有序数字,中位数 mid
所在的位置可以将有序数列分割为长度相等的两部分 l_part
和 r_part
,即有 len(l_part) == len(r_part)
,并且满足两部分中的所有数字满足 max(l_part) <= min(r_part)
。
对于两个有序数组 nums1
和 nums2
,长度分别为 m
和 n
,算法的思路是在 nums1
中找到位置 i
上的元素,在 nums2
中找位置 j = (m+n)/2-i
上的元素,这样便可满足 (i+j) == (m+n)/2
,可将两数组分为长度相等的两部分。
其中 nums1[i]
和 nums2[j]
为后半部分的最小的两个元素,(i+j)
为前半部分的长度,nums1[i-1]
和 nums2[j-1]
为前半部分的最大的两个元素。那么中位数需要同时满足:
nums1[i-1] <= nums2[j]
和 nums2[j-1] <= nums1[i]
。
注意应该满足 m <= n
,如此当 i >= 0 && i <= m
时,可保证 j = (m+n)/2-i
中的 j <= n && j >= 0
。如果同时 n == 0
,则表示两个数组都没有元素,这不是正常数据。
当某个 i
和 j
不能同时满足 nums1[i-1] <= nums2[j]
和 nums2[j-1] <= nums1[i]
时,需要考虑如何修正 i
的值。
查找 i
使用二分查找,start,end = 0,m
(
(start,end]
(
s
t
a
r
t
,
e
n
d
]
),i = (start+end)/2
,当 start <= end
时:
如果 nums1[i-1] > nums2[j]
,那么需要减小 nums1[i-1]
的值,nums2[j]
的值也会随之增大,所以修正方法是 end = i-1
,满足条件的 i
在前 i-1
部分。
如果 nums2[j-1] > nums1[i]
,那么需要增大 nums1[i]
的值,nums2[j-1]
的值也会随之减小,所以修正方法是 start = i+1
,满足条件的 i
在后 end-(i+1)
部分。
当找到满足条件的 i
和 j
之后,因为 (i+j) == (m+n)/2
如果 (m+n)%2 == 1
,则中位数为
r = min(nums1[i],nums2[j]);
mid = r;
如果 (m+n)%2 == 0
,则中位数应该时
l = max(nums1[i-1],nums2[j-1]);
r = min(nums1[i],nums2[j]);
mid = (l+r)/2;
现在需要考虑边界条件,即 i == 0
,i == m
,j == 0
和 j == n
。
因为有 j = (m+n)/2-i
的约束条件,所以当 i > 0
必有 j < n
,当 i < m
必有 j > 0
。故可在查找 i
的判断过程中添加相应的约束条件:
while(start<=end){
if(i>0 && nums1[i-1]>nums2[j])
end = i-1;
else if(i<m && nums[j-1]>nums[i])
start = i+1;
else break;
}
找到满足条件的 i
和 j
之后,对于求 r
时:
// 不可能同时有 i == m && j == n
if(i == m) r = nums2[j];
else if(j == n) r = nums1[i];
else r = min(nums1[i],nums2[j]);
if((m+n)%2 == 1) return r;
对于求 l
时:
//不可能同时有 i == 0 && j == 0
if(i == 0) l = nums2[j-1];
else if(j == 0) l = nums1[i-1];
else l = max(nums1[i-1],nums2[j-1]);
return (l+r)/2.0;
这样便能够求得最终结果,算法复杂度为 O(logmin(m,n)) O ( log m i n ( m , n ) ) 。