给定两个大小为 m 和 n 的有序数组 nums1 和 nums2。
请你找出这两个有序数组的中位数,并且要求算法的时间复杂度为 O(log(m + n))。
你可以假设 nums1 和 nums2 不会同时为空。
思路:
因为需要logn的时间复杂度,所以考虑用二分法求解。具体答案参考官方给出的解释:https://leetcode-cn.com/problems/median-of-two-sorted-arrays。
大致思路是寻找i,j分别把两个数组截成左右两部分。两个左边部分构成的集合元素的数量等于两个右边部分构成的集合元素的数量(两个数组和为奇数则左集合比右集合多1)。此时中位数就可以由左集合的最大值与右集合的最小值共同确定。又因为j可以由i计算得到,所以实际上就是通过二分法寻找i,使得i,j满足上述条件。
#include <iostream>
#include <vector>
using namespace std;
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int x=(int)nums1.size();
int y=(int)nums2.size();
//确保是在短的数组上寻找i,否则通过((x+y+1)/2)-i计算j会出现负数。
vector<int> a,b;
if(x>y){
a=nums2;
b=nums1;
int tmp=x;
x=y;
y=tmp;
}
else{
a=nums1;
b=nums2;
}
int aLeft=0,aRight=x;
int halfPos=(x+y+1)/2;
while(aLeft<=aRight){
int i=(aLeft+aRight)/2;
int j=halfPos-i;
//i太大,在左半边二分查找
if(a[i-1]>b[j] && i>aLeft){
aRight=i-1;
}
//i太小,在右半边二分
else if(a[i]<b[j-1] && i<aRight){
aLeft=i+1;
}
else{
//i刚好时,中位数由左集合的最大值和右集合的最小值确定
double leftMax;
//考虑边界情况,i==0时,左集合只有b的元素
if(i==0) leftMax=b[j-1];
//j==0时,左集合只有a的元素
else if(j==0) leftMax=a[i-1];
else leftMax=max(b[j-1],a[i-1]);
if((x+y)%2==1) return leftMax;
double rightMin;
if(i==x) rightMin=b[j];
else if(j==y) rightMin=a[i];
else rightMin=min(a[i],b[j]);
return (leftMax+rightMin)/2.0;
}
}
return 0.0;
}
};
int main(int argc, const char * argv[]) {
vector<int> input1{1,3};
vector<int> input2{2};
Solution s;
cout<<s.findMedianSortedArrays(input1, input2);
return 0;
}