算法题目
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)).
算法分析
这个题目要求实际上挺严格的,上来就直接规定时间复杂度为O(log(m+n)),所以我们必须要好好利用起已经排好序的这个条件。看到log的时间复杂度,我们不难想到要用分治的思想。但一开始的时候我太过于纠结中值,而不能在解答全局来看,导致进入了死胡同。至于这个分治怎么使用,我一开始也没想到,后来查了一下解法,发现只要我们不要把他想成找中值,而要想成找第k小的数(在本题中k= (m+n)/2),这样就很容易进行递归运算。
比如一开始是在第k大的数,那么比较A[k/2-1]与B[K/2-1],如果B[K/2-1]>A[k/2-1],那么就证明A[0]~A[k/2-1]之间的数都应该比这两个数组的中值要小,所以就可以剔除这k/2个数,这么一来,问题从找到第k小的数就转换为找第k/2小的数了。依次类推,找到k=0时,就只需要比较A’[0]和B’[0]哪个数较小就可以找到所需要的数了。
分析一下时间复杂度是O(logk)=O(log(m+n)/2)=O(log(m+n)符合题目要求。
我写的代码中没有用递归的方法,所以代码比较杂乱,但是主要思想还是一样的。
double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) {
int right1;
int right2;
if(!nums1.empty())
right1 = nums1.size()-1;
else right1 = -1;
int left1 = 0;
if(!nums2.empty())
right2 = nums2.size()-1;
else right2 = -1;
int left2 = 0;
int tot_length = right1+right2+2;
bool isodd= true;
if(tot_length%2==0) isodd= false;
int k = (tot_length-1)/2;//找到合并之后下标为k的数
while(k>0&&left1<=right1&&left2<=right2){
int tem =max(k/2-1,0); //每次循环可以剔除一半的k的数量
//避免越界
if(left1+tem>=right1){
tem = right1-left1;
}
if(left2+tem>=right2){
tem = right2-left2;
}
if(nums1[left1+tem]>nums2[left2+tem]){
//剔除nums2的较小的
left2+=tem+1;
}
else {
left1+=tem+1;
}
k-=tem+1;
}
if(left1>right1) {
if(isodd) return nums2[left2+k];
else return (double)(nums2[left2+k]+nums2[left2+k+1])/2;
}
if(left2>right2) {
if(isodd) return nums1[left1+k];
else return (double)(nums1[left1+k]+nums1[left1+k+1])/2;
}
if(isodd){
if(nums1[left1]>nums2[left2]) return nums2[left2];
else return nums1[left1];
}
else{
int t;
if(nums1[left1]>nums2[left2]) {
t= nums2[left2];
left2++;}
else {t=nums1[left1];left1++;}
if(left1>right1) return (double)(t+nums2[left2])/2;
if(left2>right2) return (double)(t+nums1[left1])/2;
if(nums1[left1]>nums2[left2])
return (double)(t+nums2[left2])/2;
else return (double)(t+nums1[left1])/2;
}
}