Problemn
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)).
思路
很不好想的一道题!首先想到的是合并两个排序数组然后再选取其中位数。这样时间复杂度是线性不符合他的要求。如果是log的复杂度应该考虑二分法。这个题的关键就在于如何二分。
我自己实在想不到什么办法,参考一下前人的做法:
http://www.cnblogs.com/yuzhangcmu/p/4138184.html
http://algorithmsandme.in/2014/12/find-kth-smallest-element-in-two-sorted-arrays/
中位数可以泛化为取第k小的元素问题,思路如下:
在两个排序数组A中取前k/2个元素,B中取前k-k/2个元素,比较第k/2、k-k/2个元素大小,A[k/2-1] and B[k-k/2-1],如果A[k/2-1]>B[k-k/2-1], 我们假设在B的k-k/2-1位之后找到一个元素B[x]和A[k/2-1]相等,如果合并A[0] ~ A[k/2-1]和B[0] ~ B[x],得到的新数组是前k/2+(x+1)小的元素,这里x>k-k/2-1, k/2+x+1>k。第k个元素一定在这个新数组中,所以我们可以舍弃A中k/2-1之后的部分。同理我们假设在A的k/2-1位之前找到一个元素A[y]和B[k-k/2-1]相等,合并A[0] ~ A[y] and B[0] ~ B[k-k/2-1],得到的新数组长度小于k,第k哥元素一定不在这个新数组中,由此我们可以舍弃B中B[k-k/2-1]与其之前的部分。一图以蔽之:
红色表示我们可以舍弃不考虑的部分,绿色表示第k个元素可能的位置。
现在我们确定k/2个元素或者k-k/2个元素比k小,如果A[k/2-1]>B[k-k/2-1],此时既是上图的情况,红色的部分被扔掉。我们确定的是B中被扔掉的部分都小于我们要求的第k个元素。所以下一步所求是在绿色数组中求第k-k/2小的元素。如果A[k/2-1]<B[k-k/2-1], 此时是上图中绿色的部分要被扔掉,我们需要在红色的数组中求第k-(k-k/2)=k/2个元素。而如果A[k/2-1]=B[k-k/2-1], A[k/2-1]即为第k个元素。分治法解决之。
上代码
public class Solution {
public double findMedianSortedArrays(int[] nums1, int[] nums2) {
if((nums1.length+nums2.length)%2==0){
return (findKth(nums1, nums2, (nums1.length+nums2.length)/2+1)+findKth(nums1, nums2, (nums1.length+nums2.length)/2))/2.0;
}
return findKth(nums1, nums2, (nums1.length+nums2.length)/2+1);
}
private int findKth(int[] nums1, int[] nums2, int k){
return findKHelper(nums1, 0, nums1.length-1, nums2, 0, nums2.length-1, k);
}
private int findKHelper(int[] nums1, int left1, int right1, int[] nums2, int left2, int right2, int k){
if(left1>right1){
return nums2[left2+k-1];
}else if(left2>right2){
return nums1[left1+k-1];
}
if(k==1){
return Math.min(nums1[left1], nums2[left2]);
}
int search1 = k/2;
int search2 = k-k/2;
int key1 = left1+search1-1>right1?Integer.MAX_VALUE:nums1[left1+search1-1];
int key2 = left2+search2-1>right2?Integer.MAX_VALUE:nums2[left2+search2-1];
if(key1>key2){
return findKHelper(nums1, left1, Math.min(right1, left1+search1-1), nums2, left2+search2, right2, k-search2);
}else if(key1<key2){
return findKHelper(nums1, left1+search1, right1, nums2, left2, Math.min(left2+search2-1, right2), k-search1);
}else{
return key1;
}
}
}
复杂度是k的对数,此例中k~1/2(N+M),总复杂度为log(N+M)。满足条件要求。