题目描述
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 ) ) 。
339

被折叠的 条评论
为什么被折叠?



