这是我做的第一道hard的题,因为看到时间限制为O(log(m+n)),所以想到了要用divide and conquer。但是如何进行divide却没有很好的思路,想到了两个方案,一个是每次去掉小于第m+n/2的数,最后剩下的就是m+n/2。但是如何确定边界条件没有想好。第二个方案是每次去掉相同数量的小于m+n/2和大于m+n/2的数,转化成更小的两个数组。
最后看了http://blog.csdn.net/zxzxy1988/article/details/8587244发现第一种思路是可行的。
可以把问题转化成求第k个数的问题。首先假设A元素个数小于B分别为m,n。如果数组A和数组B元素个数都大于k/2,那么比较A[k/2-1]和B[k/2-1]。比较结果分三种情况:
1.A[k/2-1]<B[k/2-1]
2.A[k/2-1]==B[k/2-1]
3.A[k/2-1]>B[k/2-1]
情况一可以推出A中前k/2个数都小于合并后的第k个数,因为A[k/2-1]最多大于A中的k/2-1以及B中的k/2-1个数,所以A[k/2-1]最多是合并后的第k-2个数。因此可以舍去A中前k/2个数。此时k变成k-k/2。
情况而可以直接看出A[k/2-1]或B[k/2-1]是第k个数。
情况三和情况一一样。
因此可以形成递归,最后会遇到如下边界条件:
当A为空或,返回B[K-1]
当k=1,返回max(A[0],B[0])
此外,如果A小于k/2那么可以比较A[m-1]和B[k-m-1]后面的情况同上。
时间复杂度:总共去掉k个数,最好情况每次去掉一半,需要时间logk。因为k=(m+n)/2所以时间复杂度log((m+n)/2)
/**
* Created by marsares on 15/6/3.
*/
public class MedianOfTwo {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
int sum=nums1.length+nums2.length;
if(sum%2!=0)return findKthSortedArrays(nums1,nums2,(sum+1)/2,0,0);
else return (findKthSortedArrays(nums1,nums2,sum/2,0,0)+findKthSortedArrays(nums1,nums2,sum/2+1,0,0))/2;
}
public double findKthSortedArrays(int[]nums1,int[]nums2,int k,int m,int n){
if(nums1.length-m>nums2.length-n){
return findKthSortedArrays(nums2,nums1,k,n,m);
}
if(nums1.length-m==0)return nums2[n+k-1];
if(k==1){
if(nums1[m]>nums2[n])return nums2[n];
else return nums1[m];
}
int pa=min(k/2,nums1.length-m);
if(nums1[m+pa-1]<nums2[n+pa-1])return findKthSortedArrays(nums1,nums2,k-pa,m+pa,n);
else if(nums1[m+pa-1]==nums2[n+pa-1]&&pa==nums1.length-m)return findKthSortedArrays(nums1,nums2,k-pa,m+pa,n);
else if(nums1[m+pa-1]==nums2[n+pa-1]&&k%2!=0&&pa==k/2)return findKthSortedArrays(nums1,nums2,k-pa,m+pa,n);
else if(nums1[m+pa-1]==nums2[n+pa-1])return nums1[m+pa-1];
else return findKthSortedArrays(nums1,nums2,k-pa,m,n+pa);
}
private int min(int a,int b){
if(a<=b)return a;
else return b;
}
public static void main(String[]args){
int[]nums2={2};
int[]nums1={1,3,4};
MedianOfTwo mot=new MedianOfTwo();
System.out.println(mot.findKthSortedArrays(nums1,nums2,3,0,0));
}
}