Desciption
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)).
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
思路1
该方法的时间复杂度为
循环条件
对于寻找中位数的问题,我们可以把两个数组看做均一分为二为left和right两个部分,设数组A的分界坐标为i,数组B的分界坐标为j:
left_part | right_part
A[0], A[1], ..., A[i-1] | A[i], A[i+1], ..., A[m-1]
B[0], B[1], ..., B[j-1] | B[j], B[j+1], ..., B[n-1]
对于left_part和right_part有如下性质:
1) len(left_part) == len(right_part)
* i+j=m-i+n-j (or: m - i + n - j + 1)
2) max(left_part) <= min(right_part)
* A[i-1]<=B[j]
* A[i]>=B[j-1]
对于约束条件
同时由于计算机整式除法的 向下取整,为保证
则合并数组的中位数为
边界条件
从上面的分析可知,在确保条件
仔细思考,其实在这种情况下,说明,已经找到了我们所要求的
二分法找中位数
根据以上分析,我们只要遍历一遍数组A,就一定能找到所需的
init:
imin=0;
imax=m;
i=(imin+imax)/2;
while(imin<=imax){
j=(m+n+1)/2-i;
if(A[i-1]>B[j]){
//i太大,应该变小->imax=i-1
}else if(A[i]<B[j-1]){
//i太小,应该变大 -> imin=m+1
}else{
//找到了所需的i
}
}
代码
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if(nums1.empty()&&nums2.empty()){
return 0;
}
int len1,len2;
int i=0,j=0;
//保证len1<=len2
if(nums1.size()>nums2.size()){
vector<int> temp = nums2;
nums2=nums1;
nums1=temp;
}
len1=nums1.size();
len2=nums2.size();
int imin=0,imax=len1;//注意此处imax应该等于len1,而不是len1-1
int left=0,right=0;
int half_len=(len1+len2+1)/2;
while(imin<=imax){
i=(imin+imax)/2;
int j=half_len-i;
if(i>0 && nums1[i-1]>nums2[j]){
imax = i-1;
}else if(i<len1 && nums1[i]<nums2[j-1]){
imin = i+1;
}else{
//找到了正确的i和j
if(i==0){
left = nums2[j-1];
}else if(j==0){
left = nums1[i-1];
}else{
left = max(nums1[i-1],nums2[j-1]);
}
//如果两个数组长度和为奇数
if((len1+len2)%2==1){
return left;
}
if(i==len1){
right=nums2[j];
}else if(j==len2){
right=nums1[i];
}else{
right=min(nums1[i],nums2[j]);
}
return (left+right)/2.0;
}
}
//这一句根本不会执行,只是为了给一个返回
//正确结果一定会在while循环中被找到
return (left+right)/2.0;
}
};
思路2
按照常规思路,把题目变为:查找两个排序数组合并后的第k小的值,k=1,2,…,m+n,则应用二分法,其复杂度为
在这种情况下,要注意的是两个数组的奇偶数情况的处理。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
if(nums1.empty()&&nums2.empty()){
return 0;
}
int len1,len2;
len1=nums1.size();
len2=nums2.size();
if(len1==0&&len2==0){
return 0;
}
//k=1,2...,len1+len2
int k1=(len1+len2+1)/2;
int k2=(len1+len2+2)/2;
//传入有效下标
return (getKth(nums1,0,len1-1,nums2,0,len2-1,k1)+getKth(nums1,0,len1-1,nums2,0,len2-1,k2))/2.0;
}
static double getKth(vector<int> &A,int al,int ar,vector<int>& B, int bl,int br, int k){
//保证长度小的数组在前面,长度大的数组在后面
if(ar-al>br-bl){ // 其实是ar-al+1>br-bl+1
return getKth(B,bl,br,A,al,ar,k);
}
//终止条件
if(ar<al){
return B[bl+k-1];
}
if(k==1){
return min(A[al],B[bl]);
}
//使用二分法,两个个数组的步长均为k/2
int mid = k/2;
//注意此处是i-1和j-1!
//同时注意条件ar-al+1<k/2 :如果A的长度小于k/2,那么B中的前k/2位一定小于要找的resmid
if(ar-al+1<mid || A[al+mid-1]>B[bl+mid-1]){
return getKth(A,al,ar,B,bl+mid,br,k-mid);
}else{
return getKth(A,al+mid,ar,B,bl,br,k-mid);
}
}
};