给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
示例 1:
nums1 = [1, 3]
nums2 = [2]
则中位数是 2.0
示例 2:
nums1 = [1, 2]
nums2 = [3, 4]
则中位数是 (2 + 3)/2 = 2.5
昨天忙着调区块链的coursework忘了……今天补上。
这题有点难……最初的想法当然是最简单的,将两个数组合并,排序然后求中位数,但是时间复杂度就是O(m+n),题目要求O(log(m+n)),想到了要用二分法来做,但是没想好怎么实现,学习了网上大神们的思路(转载):
其实可以把寻找中位数,转变为寻找数组第k小的数。
a数组长度为n,b数组长度为m;
首先,找a和b两个有序数组中第K小,就是在a中找某个位置i,在b中找某个位置j,其满足条件为:
1、i+j=k
2、a[i-1]<=b[j]&&b[j-1]<=a[i]
这样第K小即为:max(a[i-1],b[j-1]);
其次,我们就可以在a数组中二分查找位置i,相应b中位置j=k-i,但是要注意b中j的位置不能越过b的边界即:0<=j<=m,
这样可以得到在a数组中二分查找的范围:0<=i<=n且k-m<=i<=k即max(0,k-m)<=i<=min(k,n);
我们可以在这个范围内用二分模板查找i的位置。
最后,二分找到i即代码中的le后,注意边界判断如果位置i和j前面都有元素,第k小=max(a[i-1],b[j-1]);如果i=0,
第k小=b[j-1];如果j=0;第k小=a[i-1];
两个有序数组的中位数即为:1、两个数组长度(m+n)为奇数,求第(m+n)/2+1小元素;2、两个数组长度(m+n)为偶数,求
第(m+n)/2小、第(m+n)/2+1小,两者平均值。
提交代码:
class Solution {
public:
int findKthIndex(vector<int>& nums1, vector<int>&nums2, int k){
assert(1<=k && k<= nums1.size() + nums2.size());
int left = max(0,int(k-nums2.size())), right = min(int(nums1.size()),k);
while (left < right){
int p = left+(right-left)/2;
if (nums2[k-p-1] > nums1[p]){
left = p + 1;
}
else{
right = p;
}
}
int n1=left == 0 ? INT_MIN : nums1[left - 1];
int n2=left == k ? INT_MIN: nums2[k-left-1];
return max(n1,n2);
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int flag = (nums1.size() + nums2.size()) % 2;
int k = (nums1.size() + nums2.size()) / 2;
if (!flag){
return (findKthIndex(nums1,nums2,k) + findKthIndex(nums1,nums2,k+1)) / 2.0;
}
else
return findKthIndex(nums1,nums2,k+1);
}
};