给定两个大小为 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
此题是两个有序数组中查找第K小的数的特例,而我能想到的查找第K个元素便是使用归并排序算法(邓公的<<数据结构>>讲的非常不错)。所以,一开始我是按照归并排序的思路+第K个元素停止的来做的。但一开始我没想到可以把整个查找函数提取出来进行封装,当时写的有点复杂。
在查看一些解题思路后,得到启发,把查找函数提出来后,代码易读性与简洁性得到了很大的提升。
关于时间复杂度,题目要求O(log(n+m)),但此思路的时间复杂度为O(n+m),一般情况下的时间复杂度默认最坏时间复杂度。因此在时间复杂度的要求上,这个思路是不满足的。但从提交的结果来看,算法实际消耗的时间还是可以令人满足的。
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int xSize=nums1.size();
int ySize=nums2.size();
int total = xSize+ySize;
if((xSize+ySize)&0x01) return find_Kth(nums1,xSize,nums2,ySize,total/2+1);
else return (find_Kth(nums1,xSize,nums2,ySize,total/2)+find_Kth(nums1,xSize,nums2,ySize,total/2+1))/2;
}
private:
double find_Kth(vector<int>& nums1,int xSize,vector<int>& nums2,int ySize,int target){
int xIndex=0;
int yIndex=0;
int loken=0;
double value;
while(xIndex<xSize||yIndex<ySize){
if((xIndex<xSize)&&(!(yIndex<ySize)||nums1[xIndex]<=nums2[yIndex])){
value=nums1[xIndex];
xIndex++;
loken++;
if(loken==target) return value;
}
if((yIndex<ySize)&&(!(xIndex<xSize)||(nums2[yIndex]<nums1[xIndex]))){
value=nums2[yIndex];
yIndex++;
loken++;
if(loken==target) return value;
}
}
return 0;
}
};
设定ia,ib。其中ia、ib满足一下条件:
当A[ia]=B[ib]时,因为ia+ib=k,所以第k个元素=A[ia]=B[ib],返回A[ia]或B[ib];
当A[ia]
这个算法的思路实现并不算难,但是难就难在了边界条件的确定。目前对于这一块,我并没有很深入的理解,可能需要一定的题量支持。就对三个边界发生的情况做下解释:
class Solution {
public:
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
const int m=nums1.size();
const int n=nums2.size();
int total=m+n;
if(total&0x01)
return find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1);
else
return (find_Kth(nums1.begin(),m,nums2.begin(),n,total/2+1)+find_Kth(nums1.begin(),m,nums2.begin(),n,total/2))/2;
}
private:
double find_Kth(vector<int>::const_iterator A,int m,vector<int>::const_iterator B,int n,int k){
if(m>n) return find_Kth(B,n,A,m,k);
if(m==0) return *(B+k-1);
if(k==1) return min(*A,*B);
int ia=min(k/2,m);
int ib=k-ia;
if(*(A+ia-1)<*(B+ib-1)) return find_Kth(A+ia,m-ia,B,n,k-ia);
else if(*(B+ib-1)<*(A+ia-1)) return find_Kth(A,m,B+ib,n-ib,k-ib);
else return A[ia-1];
}
};
Leetcode 题解
Leetcode