-
题目:
给定两个大小为 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.归并排序思路,排序到第(n1+n2)/2个。时间复杂度O{(m+n)/2}
b.二分搜索思想。
log级别的肯定想到二分查找。
按中位数的定义,问题求解变成:
1.len(leftpart)==len(rightpart)
2.max(leftpart)<=min(rightpart)
3.median=(max(leftpart)+min(rightpart))/2. -
代码:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { //采用归并排序思想,mergesort
int n1=nums1.size(),n2=nums2.size();
int stop=(n1+n2)/2; //排序到0-(n1+n2)/2
int tmp1=0,tmp2=0;
int i=0,j=0,k=0;
//归并排序思路。tmp1,tmp2保存排好序的最后两位数
while(i<n1&&j<n2&&k<=stop){
if(nums1[i]<=nums2[j]){//num1中的数小,则将num1[i]归并
tmp1=tmp2;
tmp2=nums1[i];
i++;k++;
}
else{//否则将num2[j]归并,
tmp1=tmp2;
tmp2=nums2[j];
j++;k++;
}
}
//其中一个数组已经归并完成,但还没到stop
while(k<=stop&&i<n1){
tmp1=tmp2;
tmp2=nums1[i];
i++;k++;
}
while(k<=stop&&j<n2){
tmp1=tmp2;
tmp2=nums2[j];
j++;k++;
}
if((n1+n2)%2) return tmp2; //奇数个,返回中间值
else return (tmp1+tmp2)/2.0; //偶数个,返回平均中间值。
}
};
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int n1=nums1.size();
int n2=nums2.size();
if(n1>n2) //保证数组1一定最短
return findMedianSortedArrays(nums2,nums1);
int L1,L2,R1,R2,C1,C2,low=0,high=2*n1;
while(low<=high){//二分
C1=(low+high)/2;//C1是二分的结果。
C2=n1+n2-C1;//关键点
L1=(C1==0)?INT_MIN:nums1[(C1-1)/2];//nums1整体比中位数大,只能选L2
R1=(C1==2*n1)?INT_MAX:nums1[C1/2];//nums1整体比中位数小,只能选R2
L2=(C2==0)?INT_MIN:nums2[(C2-1)/2]; //num2整体比中位数大,只能选L1;
R2=(C2==2*n2)?INT_MAX:nums2[C2/2];//nums2整体比中位数小,只能选R1
if(L1>R2)//C1割太大,左移
high=C1-1;
else if(L2>R1)//C1割太小,右移
low=C1+1;
else //找到合适的分割,即在两个数组中,整个左部小于整个右部
break;
}
return (max(L1,L2)+min(R1,R2))/2.0;
}
};