题目
给定两个大小为 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
分析
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<=k-i<=m,
这样可以得到在a数组中二分查找的范围:0<=i<=n且k-m<=i<=k即max(0,k-m)<=i<=min(k,n);
我们可以在这个范围内用二分模板查找i的位置。
最后,二分找到i即代码中的le后,注意判断b[j-1]和a[i-1]是否越界。
两个有序数组的中位数即为:1、两个数组长度(m+n)为奇数,求第(m+n)/2+1小元素;2、两个数组长度(m+n)为偶数,求第(m+n)/2小、第(m+n)/2+1小,两者平均值。
代码
class Solution {
public:
int findKthElm(vector<int>& nums1,vector<int>& nums2,int k){
int le=max(0,int(k-nums2.size())),ri=min(k,int(nums1.size()));
while(le<ri){//le和ri是i的范围
int m=le+(ri-le)/2;
if(nums2[k-m-1]>nums1[m]) le=m+1;//不满足b[j-1]<=a[i]则i太小了右移
else ri=m;
}//循环结束时的位置le=ri即为所求位置,第k小即为max(nums1[le-1]),nums2[k-le-1])
int nums1LeftMax=le==0?INT_MIN:nums1[le-1];//边界判断
int nums2LeftMax=le==k?INT_MIN:nums2[k-le-1];//边界判断
return max(nums1LeftMax,nums2LeftMax);
}
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n=nums1.size()+nums2.size();
if(n&1)
return findKthElm(nums1,nums2,(n>>1)+1);
else
return (findKthElm(nums1,nums2,n>>1)+findKthElm(nums1,nums2,(n>>1)+1))/2.0;
}
};